大表优化方案
一、Mysql出现性能问题
- 表数据量过大
- sql查询太复杂,基于Sql语句的优化,比如最左匹配原则,用索引字段查询、降低sql语句的复杂度等
- sql查询没走索引,根据业务调整sql走索引查询或者增加索引
- 数据库服务器的性能过低,器硬件升级
除了大表其他的参考Mysql性能优化
二、表数据过大的解决方案
之前讲过Mysql三层B+树大约可以存储千万级数据量,超过这个就算大表。当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
1. 限定数据的范围
禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。
2. 读/写分离
主库负责写,从库负责读,这个是经典的数据库拆分方案
3、分表分库
包括冷热数据分离、历史数据归档等
3.1、垂直分区
根据数据库里面数据表的相关性进行拆分。简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
垂直拆分的优点: 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
3.2、水平分区
保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。
水平拆分是指数据表行的拆分,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。
注意分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库 。
4、分库分表会带来的问题
- 非分片键查询,解决:非分片键和分片键建立映射关系或者k-v存储映射关系
- 分库之后数据库之间的数据同步问题,解决:双写
- 分页、排序,解决:业务端做聚合, 存储在nosql
- 跨库查询即跨节点Join性能较差,逻辑复杂,解决:Sharding-JDBC
- 分片事务,解决:Sharding-JDBC
分库分表有两种常见解决方案:
- 客户端代理: 分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。 当当网的 Sharding-JDBC、阿里的TDDL是两种比较常用的实现。
- 中间件代理: 在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。 Mycat 、360的Atlas、网易的DDB等等都是这种架构的实现。
具体的有哪些解决方案:
- Sharding-Sphere(5.x)
- Sharding-JDBC -> 客户端代理
- Sharding-Proxy ->中间件代理
- Mycat
- 中间件代理
5、分库分表之后,id 主键如何处理
6、常见的分表策略
- 哈希取模分片
- 缺点是在需要表扩容的时候,这种情况下,就需要对原来的数据进行整体迁移
- 一致性hash算法
- 缺点是hash环偏斜,解决虚拟节点的方式
- -按照范围分片
具体参考Sharding-JDBC
三、总结
根据多年工作经验建议尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O以及维护中间的高可用带来的各种复杂度。