当一张表数据量达到 2亿条 以上时,即使有主从库,也可能遇到以下问题:
- 查询变慢,索引树过大,点查延迟明显。
- 批量写入、归档效率低。
- 表结构变更(DDL)风险高。
这时,就需要考虑 水平拆分(分库/分表)。本文结合一个“点查为主”的业务场景,介绍如何安全、平滑地完成大表拆分。
1. 拆分思路
1.1 为什么拆分
- 减少单表数据量,提升查询和维护效率。
- 提高系统扩展性,支持未来数据继续增长。
1.2 拆分方式
水平分表:在同一个库里创建多张表,把数据均匀切开。
- 优点:运维简单,迁移快。
- 缺点:数据库单点压力仍然存在。
水平分库 + 分表:把数据拆到多个库里,每个库再分多张表。
- 优点:扩展性最强,单库压力小。
- 缺点:改造成本高,涉及分布式事务和路由。
如果只是单库,先做水平分表即可。
2. 拆分方案设计
假设有一张订单表 order
,2亿条数据,查询条件以 订单号点查 为主:
2.1 分片键选择
- 订单ID(order_id):自增或雪花算法生成,能均匀分布。
- 取模方式:例如
order_id % 16
→ 把数据拆到 16 张表。
2.2 新表设计
1 | order_00 |
与原表结构完全一致。
2.3 路由规则
- 写入:按
order_id % 16
选择目标表。 - 查询:由代码或中间件(如 ShardingSphere、MyCat)根据 ID 定位表。
3. 数据迁移流程
为了保证 生产安全,迁移必须采用 灰度切流 + 双写 + 校验 的方式:
步骤 1:准备环境
- 创建分表
order_00
…order_15
。 - 配置好代码里的路由逻辑(支持新老表双写)。
步骤 2:灰度切流
- 先让一部分新写入(比如 1% 用户)走新表,其他仍然写老表。
- 验证新表能正常查询、写入。
步骤 3:历史数据迁移
使用迁移脚本(推荐 批量+限速 的方式):
1
2
3
4
5INSERT INTO order_03 (col1, col2, ...)
SELECT col1, col2, ...
FROM order
WHERE order_id % 16 = 3
LIMIT 10000;配合任务调度器分批跑,避免锁表。
步骤 4:双写校验
迁移期间,写操作同时写入老表和新表。
定期做 数据校验:
行数比对:
1
2SELECT COUNT(*) FROM order WHERE order_id % 16 = 3;
SELECT COUNT(*) FROM order_03;校验哈希:对比 MD5/SUM 聚合。
步骤 5:全量切换
- 确认迁移完成、校验通过后,关闭老表写入。
- 所有请求统一走新表。
步骤 6:回收老表
- 观察一段时间后,老表只保留归档数据,或直接下线。
4. 风险与安全保障
不影响生产:
- 迁移分批次+限流,避免一次性锁全表。
- 业务代码支持双写,保证数据一致。
回滚预案:
- 灰度期间若新表有问题,立即回切老表。
- 保证老表在迁移前始终可用。
监控报警:
- 校验迁移速率、落库延迟。
- 重点监控主从延迟和慢查询。
5. 总结
- 拆分本质:减少单表压力,提升扩展性。
- 点查业务:适合用主键取模分表。
- 迁移原则:灰度切流 → 双写迁移 → 数据校验 → 全量切换。
- 生产保障:限速迁移、校验数据、保留回滚预案。
一句话记忆:
“小步快跑,双写保命,先灰度再全量”。