数据库单表拆分有关问题
本期焦点问题:单一数据库内分表
本期多个项目出现了在单一数据库内分表的情况,典型的做法是:
某个表(表A)预期会有几千万乃至上亿条数据,于是在单库内拆分成若干张独立的表: A_1, A_2, A_3, … , A_n,用“表名+后缀”来区分。
在绝大多数情况下,这并不是合适的做法,下表给出了库内分表对一些关键指标的影响:
项目 |
库内分表 |
应用开发难度 |
比单表高 需要管理数据的路由,跨表查询,排序等都较复杂。 |
未来拆库难度 |
比单表高 需要对多个表进行数据迁移,同时应用 |
表结构变更的难度 |
比单表高 除了耗时,还要变更多个表。 |
查询性能 |
走索引,和单表无明显差别。 全表扫描,如果并发执行,会比单表快一些。 |
写入性能 |
和单表比无明显差别 |
并发性能 |
对行锁无影响,会减少表锁冲突,但是按主键更新不加表锁。 |
从上表可以看出,库内分表提供的好处非常微小,而且在我们的业务场景下也基本用不到这些好处。但是却带来程序设计、运维等多方面的困难,
基于这些因素,我们不赞成使用库内分表这种设计方式。
那当库表出现以下几种情况时,如何来应对?
1. 记录数高
一般我们不建议单表出现1千万行以上的数据。如果业务上出现了这样的数据,首先要考虑的是通过归档来降低数据量。
归档可以有效把冷热温数据分开,同时,温数据还可以设计成在低级别SLA下提供服务。
对于不能归档的数据,主要是主数据,如用户,商品。可根据tps/qps及它们之间的比例、应用对数据一致性的要求、磁盘空间的大小来决定是做读写分离或水平拆分。
但主数据一般都是高访问量的共享数据,正常应该通过拆库来保证性能。
2. 慢查询
慢查询的出现不能想当然归于表的记录数太多,表的记录数和慢查询之间并没有必然的关系。慢查询出现的常见原因:
l 没有正确使用索引或索引失效,导致全表扫描了
l 表设计不合理,出现了多表Join
l SQL本身的写法有问题,出现了大量的中间结果
l SQL返回结果集过大
所以慢查询应该重点从表的设计和SQL的写法上去解决,库内分表不是一个好的方案。
3. TPS/QPS高
TPS高是拆库的最重要的依据,比如说一些订单表,优惠券表等大表都有数亿条数据,拆分的首要原因就是TPS撑不住了,超过6K从库就会开始有明显延迟。
如果TPS不高但QPS很高,而且对数据的一致性要求不高,可以考虑读写分离方案。