水平拆分适用于单表数据量达千万至亿级导致查询慢、主从延迟高、备份恢复慢等场景,需自行处理路由、聚合、全局统计及分布式ID;垂直拆分则按列分离冷热数据或更新频率差异大的字段,降低I/O与锁竞争,不改变查询逻辑;混合拆分常见但复杂度高,须统一元数据管理。

水平拆分适合单表数据量爆炸,但得自己管路由和聚合
当一张表超过千万甚至上亿行,查询变慢、主从延迟拉高、备份恢复耗时,这时候水平拆分(Sharding)才真正有用。它把同一张表的数据按某种规则(比如 user_id % 4)分散到多个物理库/表中,每份只存一部分数据。
但代价明显:你得在应用层或中间件里实现分片键识别、SQL 路由、跨分片 JOIN 或 GROUP BY 的结果合并;SELECT COUNT(*) 这种全局统计必须改写成多节点并发查再汇总;自增主键基本废掉,得换 UUID 或雪花算法。
常见踩坑点:
- 误把高频关联字段(如
order.user_id和user.id)设成不同分片键,导致跨库JOIN不可避免 - 用时间范围做分片(如按月建表),但业务查的是“最近 7 天订单”,结果要扫 2–3 张表,反而更慢
- 没预留扩容能力,初始分 4 片,等流量翻倍后发现没法平滑加到 8 片,只能停机迁移
垂直拆分解决耦合与冷热分离,但别拆过头
垂直拆分是把一张宽表按列拆成多张逻辑相关的表,比如把 user 表拆成 user_base(登录名、密码)、user_profile(昵称、头像)、user_stats(积分、等级)。目标是降低单表宽度、减少 I/O、隔离读写压力、方便按需扩缩容。
它不碰行数,所以不用改查询逻辑,也不影响主键和事务。但拆得不合理会引入大量关联查询,反而加重数据库负担。
实用建议:
- 优先拆“更新频率差异大”的字段,比如用户密码很少改,但积分每秒都在变,放一起会导致整行锁竞争
- 把大字段(
TEXT、BLOB)单独拎出来,避免日常SELECT *拖慢所有查询 - 别为“看着整洁”而拆——例如把
created_at和updated_at单独建一张表,毫无意义
先垂直,再水平;能不拆,就不拆
90% 的性能问题其实出在索引缺失、慢 SQL、连接池配置或硬件瓶颈,而不是数据量本身。上线前先做压测,确认单库单表真扛不住了,再考虑拆分。
拆分顺序有现实约束:
- 垂直拆分成本低、风险小,能立刻缓解部分压力,适合作为第一阶段动作
- 水平拆分是“不可逆操作”,一旦开始就绑定分片逻辑,后续所有新功能都要考虑分片语义
- 很多团队卡在“想水平但不敢动”,最后用读写分离 + 缓存 + 归档老数据撑了两年,发现根本没到非拆不可的地步
混合拆分常见但容易失控,必须有统一元数据管理
真实系统往往是混合模式:用户中心垂直拆成几张表,其中 user_order 又按 user_id 水平拆了 8 个库。这种组合放大了复杂度——你既要维护字段归属关系,又要管理分片映射、跨库事务边界、分布式唯一 ID 生成策略。
最容易被忽略的点是元数据同步:
- 新增一个字段,得同步改多个库的 DDL,漏一个就会导致应用报
Unknown column - 某个分片库升级了 MySQL 版本,其他没跟上,结果
JSON_EXTRACT行为不一致,查出来空值 - 没有集中式分片配置中心,靠配置文件硬编码分片规则,上线新节点时手动改代码,出错率飙升
真正难的从来不是怎么拆,而是拆完之后,怎么让所有人(开发、DBA、运维)对“这张表现在在哪、怎么查、哪些字段属于哪一层”保持一致认知。










