目录 #
分库分表 #
垂直切分 & 水平切分 [4] #
-
垂直切分
- 垂直分库 不同的业务使用不同的数据库. eg.订单库和促销活动库
- 垂直分表 根据一张表中的字段,将一张表划分为两张表
-
水平切分
- 水平分表 将表中的某一列作为切分的条件,按照某种规则(Range 或 Hash 取模)来 切分为更小的表
- 水平分库分表 水平切换的表分布到不同机器的库中
| 切分方式 | 数据量 | 访问特点 | 适用场景 |
|---|---|---|---|
| 单库单表 | 较小 | xxx | 小规模业务 |
| 表分区 | 较大 | 热点数据比较集中 | 数据量大、历史访问少 |
| 单库多表 | 较大 | 访问热点数据分散,所有数据都会访问 | 数据量较大 |
| 多库多表 | 极大 | 并发量高、海量数据 | 高并发、大数据量 |
分片原则的总结 [3] #
- 尽可能不要使用分片,优先考虑单表优化。[规避]
- 如果必须使用分片,分片数量应该尽量少,均匀分布在多个数据节点上。
- 分片规则应提前规划选择,考虑数据增长模式、访问模式、关联性和扩容问题。
- 避免在一个事务中跨越多个分片。 [规避]
- 查询条件要优化,避免使用 “SELECT *” 的方式,尽量避免返回大量结果集,并为频繁使用的查询语句建立索引。
- 通过数据冗余和表分区等方式降低跨库 joins 的可能性。 [规避]
- 对于有时间特征的数据表,采用时间范围分片,当前活跃数据采用短跨度分片,历史数据采用长跨度分片。
- 分片的选择应该取决于最频繁的查询 SQL 的条件,避免不带 where 语句的查询 SQL。
问题&解决方案 #
分库分表带来的问题 [1] #
- 事务性问题
- 方案一:尽可能保证一个事务所操作的表分布在一个库中 [规避]
- 方案二:业务层引入分布式事务组件,如事务性消息、TCC、Seata等
- 主键唯一性问题
- 方案一:设置自增步长,采用等差数列递增
- 方案二:采用全局统一ID生成机制,如UUID、雪花算法、数据库号段等方式
- 跨库多表join问题
- 建议尽可能避免表join操作,可以采用多次查询业务层进行数据组装 [规避]
- 冗余表或冗余字段来优化跨库 JOIN 查询 [规避] [4]
- 跨库聚合查询问题 [5]
- 方案一:赛道赛马机制,每次从N个库表中查询出TOP N数据,然后在业务层代码中进行聚合合并操作 [全局视野法]
- 方案二:将经常使用到groupby、orderby字段存储到一个单一库表中,先到单一表中查询出相应数据,然后根据查询到的主键ID,到分库分表中查询详情进行返回 [二次查询法]
- 跨节点分页查询问题 [5] 跨节点分页查询问题是指在分库分表的环境下,通过某些非分库分表字段进行查询时,可能需要跨多个库或表进行查询,这会带来性能问题。解决这个问题的一种方法是使用两套数据,一套是基于分库分表的用户查询数据,另一套是基于Elasticsearch或Solr的订单数据,主要用于运营人员进行分页查询。 为了不影响订单业务性能,可以使用异步消息来实现Elasticsearch或Solr订单数据的新增和修改。 [gpt 总结] [4]
- 扩容问题 [4] 一旦动态增加表了,就会涉及到数据迁移问题 在最开始设计表数据量时,尽量使用 2 的倍数来设置表数量。当需要扩容时,也 同样按照 2 的倍数来扩容,这样可以减少数据的迁移量。
ShardingSphere-分布式事务 [2] #
| LOCAL | XA | BASE | |
|---|---|---|---|
| 业务改造 | 无 | 无 | 需要 seata server |
| 一致性 | 不支持 | 支持 | 最终一致 |
| 隔离性 | 不支持 | 支持 | 业务方保证 |
| 并发性能 | 无影响 | 严重衰退 | 略微衰退 |
| 适合场景 | 业务方处理不一致 | 短事务 & 低并发 | 长事务 & 高并发 |
参考 #
- 一文读懂数据库分库分表
- ShardingSphere-分布式事务
- MySQL 大表优化方案(长文)
- 《36 | 什么时候需要分表分库?》
- {% post_link ‘dbShardingPaging’ %} self