“数据量大了要分库分表”这句话害了不少项目。分片带来的复杂度是长期的:跨库 join 没了、事务要改成最终一致、扩容要迁移数据、运维要管更多实例。动手之前先算几个数。
第一步:现在到底多大
SELECT table_name,
table_rows,
ROUND(data_length/1024/1024, 1) AS data_mb,
ROUND(index_length/1024/1024, 1) AS index_mb
FROM information_schema.tables
WHERE table_schema = 'app'
ORDER BY data_length DESC LIMIT 10;
注意 table_rows 是估算值,InnoDB 可能偏差很大,用 COUNT(*) 核对一遍。
第二步:单表能撑多大
经验区间:
| 单表行数 | 状态 |
|---|---|
| 百万级 | 无压力 |
| 千万级 | 需要好索引,正常 |
| 亿级 | 开始吃力,考虑归档或分片 |
| 十亿级 | 必须分片 |
但行数不是唯一指标。一行 200 字节和一行的 2KB,差距很大。判断标准是索引能否装进内存:InnoDB 的 Buffer Pool 装得下热数据索引,查询就快;装不下就开始频繁磁盘 IO。
所以先看 innodb_buffer_pool_size 和数据+索引总量。4G buffer pool 撑 20G 数据,命中率还行;撑 100G 就必然抖动。
第三步:增长有多快
SELECT DATE_FORMAT(created_at,'%Y-%m') AS m, COUNT(*)
FROM orders GROUP BY m ORDER BY m DESC LIMIT 12;
每月增长 10 万行和每月 500 万行,应对策略完全不同。前者三年才 3600 万,加个归档就能跑很多年;后者一年就得上分片。
第四步:能不能不分
按性价比排序的替代方案:
- 加索引、改 SQL:八成慢查询是这个原因,不需要分片
- 归档冷数据:把两年前的订单挪到历史表,主表立刻瘦下来,业务代码几乎不用改
- 读写分离:读多写少的场景,加从库能扛很久
- 分区表:按时间分区,查询自动裁剪分区,对应用透明
- 换存储:日志类数据放 ES 或 ClickHouse,别硬塞 MySQL
这些做完还不够,再考虑分片。
真要分,怎么分
- 分片键:必须能覆盖绝大多数查询条件。订单表按 user_id 分,按订单号查就要扫描所有分片
- 分片数量:一次分够,比如 16 或 32,后续扩容用“双倍扩容 + 数据迁移”,比一开始分 4 个再慢慢加省事
- 跨片查询:提前想好“按时间统计”“按状态查”这类需求怎么处理,通常要异构一份到宽表或搜索引擎
- 分布式事务:尽量用“本地事务 + 消息最终一致”,别上 XA
我的结论
绝大多数项目在千万级以内,靠索引 + 归档 + 读写分离就能撑很多年。分片是最后一张牌,打出去就收不回来。先把前面几步做扎实,比急着分片更有价值。
- THE END -
最后修改:2023年8月12日
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://mi-blog.cn/archives/674
共有 0 条评论