专栏名称: 运维帮
互联网技术分享平台,分享的力量。帮主一直坚信技术可以改变世界,从毕业到现在干了15年运维,有许多话要和你说。
目录
相关文章推荐
大皖新闻  ·  足协发通知:12名球员被全国停赛 ·  昨天  
大皖新闻  ·  足协发通知:12名球员被全国停赛 ·  昨天  
半导体行业联盟  ·  铠侠(中国)董事:整个行业一定会借AI的东风 ... ·  3 天前  
半导体行业联盟  ·  高通,官宣重大并购 ·  3 天前  
半导体行业联盟  ·  爆发了!半导体并购王炸! ·  3 天前  
OFweek维科网  ·  又一面板大厂更换董事! ·  3 天前  
51好读  ›  专栏  ›  运维帮

MySQL调优之大表处理探索那些事

运维帮  · 公众号  ·  · 2023-12-20 11:38

正文

当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:

  • 限定数据的范围:务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。

  • 优化SQL和索引

  • 缓存:使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存如Redis;

  • 读/写分离:经典的数据库拆分方案,主库负责写,从库负责读;

  • MySQL自带的分区表。无需更改代码,但是sql语句是需要针对分区表做优化的,sql条件中要带上分区条件的列,从而使查询定位到少量的分区上,否则就会扫描全部分区

  • 垂直分区,其实就是根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;

  • 水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key,为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;


【1】读写分离架构

读写分离是依赖于主从复制,而主从复制又是为读写分离服务的。因为主从复制要求slave不能写只能读(如果对slave执行写操作,那么 show slave status 将会呈现 Slave_SQL_Running=NO ,此时你需要手动同步一下slave)。

读写分离架构能提升整体负载,但是不能解决单表数据量过大的问题。

① 使用mysql-proxy代理

优点:直接实现读写分离和负载均衡,不用修改代码,master和slave用一样的帐号,mysql官方不建议实际生产中使用

缺点:降低性能, 不支持事务

② 指定数据源

使用 AbstractRoutingDataSource+aop+annotation 在dao层决定数据源。如果采用了mybatis, 可以将读写分离放在ORM层,比如mybatis可以通过mybatis plugin拦截sql语句,所有的 insert/update/delete 都访问master库,所有的select 都访问salve ,这样对于dao层都是透明。

plugin实现时可以通过注解或者分析语句是读写方法来选定主从库。不过这样依然有一个问题, 也就是不支持事务, 所以我们还需要重写一下DataSourceTransactionManager, 将read-only的事务扔进读库, 其余的有读有写的扔进写库。

当然可以使用 AbstractRoutingDataSource+aop+annotation 在service层决定数据源,可以支持事务。这种方式的缺点:类内部方法通过this.xx()方式相互调用时,aop不会进行拦截,需进行特殊处理。

【2】表分区

MySQL在5.1版引入的分区是一种简单的水平拆分,用户需要在建表的时候加上分区参数,对应用是透明的无需修改代码。

对用户来说,分区表是一个独立的逻辑表,但是底层由多个物理子表组成,实现分区的代码实际上是通过对一组底层表的对象封装,但对SQL层来说是一个完全封装底层的黑盒子。MySQL实现分区的方式也意味着索引也是按照分区的子表定义,没有全局索引。

用户的SQL语句是需要针对分区表做优化,SQL条件中要带上分区条件的列,从而使查询定位到少量的分区上,否则就会扫描全部分区,可以通过EXPLAIN PARTITIONS来查看某条SQL语句会落在那些分区上,从而进行SQL优化。

分区的好处

  • 可以让单表存储更多的数据

  • 分区表的数据更容易维护,可以通过清除整个分区批量删除大量数据,也可以增加新的分区来支持新插入的数据。另外,还可以对一个独立分区进行优化、检查、修复等操作

  • 部分查询能够从查询条件确定只落在少数分区上,速度会很快

  • 分区表的数据还可以分布在不同的物理设备上,从而高效利用多个硬件设备

  • 可以使用分区表来避免某些特殊瓶颈,例如InnoDB单个索引的互斥访问、ext3文件系统的inode锁竞争

  • 可以备份和恢复单个分区


分区的限制和缺点

  • 一个表最多只能有1024个分区

  • 如果分区字段中有主键或者唯一索引的列,那么所有主键列和唯一索引列都必须包含进来

  • 分区表无法使用外键约束

  • NULL值会使分区过滤无效

  • 所有分区必须使用相同的存储引擎


分区的类型

  • RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区。

  • LIST分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。

  • HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这个函数可以包含MySQL中有效的、产生非负整数值的任何表达式。

  • KEY分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值。


分区适合的场景

最适合的场景数据的时间序列性比较强,则可以按时间来分区,如下所示:

CREATE TABLE members (
firstname VARCHAR(25) NOT NULL,
lastname VARCHAR(25) NOT NULL,
username VARCHAR(16) NOT NULL,
email VARCHAR(35),
joined DATE NOT NULL
)
PARTITION BY RANGE( YEAR(joined) ) (
PARTITION p0 VALUES LESS THAN (1960),
PARTITION p1 VALUES LESS THAN (1970),
PARTITION p2 VALUES LESS THAN (1980),
PARTITION p3 VALUES LESS THAN (1990),
PARTITION p4 VALUES LESS THAN MAXVALUE
);

查询时加上时间范围条件效率会非常高,同时对于不需要的历史数据能很容的批量删除。

如果数据有明显的热点,而且除了这部分数据,其他数据很少被访问到,那么可以将热点数据单独放在一个分区,让这个分区的数据能够有机会都缓存在内存中,查询时只访问一个很小的分区表,能够有效使用索引和缓存

另外MySQL有一种早期的简单的分区实现 – 合并表(merge table),限制较多且缺乏优化,不建议使用,应该用新的分区机制来替代。

【3】垂直拆分和水平拆分

① 垂直拆分(分表、分库)

垂直分库 是根据数据库里面的数据表的相关性进行拆分,比如:一个数据库里面既存在用户数据,又存在订单数据,那么垂直拆分可以把用户数据放到用户库、把订单数据放到订单库。或者 用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆 分成两个单独的表

  • 如果数据库中的数据表过多,可以采用 垂直分库 的方式,将关联的数据表部署在同一个数据库上。

  • 如果数据表中的列过多,可以采用 垂直分表 的方式,将一张数据表分拆成多张数据表,把经常一起使用的列放到同一张表里。

垂直分表是对数据表进行垂直拆分的一种方式,常见的是把一个多字段的大表按常用字段和非常用字段进行拆分,每个表里面的数据记录数一般情况下是相同的,只是字段不一样,使用主键关联,比如原始的用户表是:

垂直拆分后是:

简单来说垂直分表是指数据表列的拆分,把一张列比较多的表拆分为多张表。把主键和一些列放在一个表,然后把主键和另外的列放在另一个表中。

垂直拆分的优点

  • 可以使得行数据变小,一个数据块(Block)就能存放更多的数据,在查询时就会减少I/O次数(每次查询时读取的Block 就少)

  • 可以达到最大化利用Cache的目的,具体在垂直拆分的时候可以将不常变的字段放一起,将经常改变的放一起

  • 简化表的结构,数据维护简单


垂直拆分的缺点

主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂。垂直拆分并不能解决单表数据量过大的问题,如果需要解决单表数据量过大还需要进行水平拆分。

如果需要解决单台服务器性能瓶颈,还需要根据模块进行垂直拆分表放到不同服务器数据库,比如订单表和台账表存放到两个数据库服务器上。这种称之为垂直分库。

有些分表的策略基于应用层的逻辑算法,一旦逻辑算法改变,整个分表逻辑都会改变,扩展性较差 对于应用层来说,逻辑算法增加开发成本管理冗余列。

② 水平分表(分库)

水平拆分是通过某种策略将数据分片来存储,分库内分表和分库两部分,每片数据会分散到不同的MySQL表或库,达到分布式的效果,能够支持非常大的数据量。前面的表分区本质上也是一种特殊的库内分表。







请到「今天看啥」查看全文