MySQL 分区表和分库分表有什么区别?什么时候用?
简化版
分区表是在同一个 MySQL 实例内把一张表按规则拆成多个分区,对应用基本透明;分库分表是把数据拆到多个表甚至多个库,应用或中间件要参与路由。分区主要解决单表管理和部分查询裁剪问题,分库分表主要解决单机容量、写入和连接压力问题。
详细版
对比:
| 维度 | 分区表 | 分库分表 |
|---|---|---|
| 拆分位置 | 同一实例内 | 多表、多库、可跨实例 |
| 应用感知 | 较低 | 较高 |
| 主要目标 | 分区裁剪、历史数据管理 | 扩展容量和吞吐 |
| 查询路由 | MySQL 优化器处理 | 应用或中间件处理 |
| 运维复杂度 | 中等 | 高 |
分区适合按时间管理历史数据、按范围删除归档、查询条件常带分区键的场景。分库分表适合单机容量或写入压力扛不住、单表过大且业务可按 shard key 路由的场景。
完整版教学
一、分区表不是分布式
分区表仍在一个 MySQL 实例里。它把一张逻辑表拆成多个物理分区,优化器在查询时如果能根据分区键判断只访问部分分区,就可以做分区裁剪。
比如按月份分区的订单表,如果查询条件带 create_time,就可能只扫目标月份分区。如果查询不带分区键,仍可能扫多个分区,收益会下降。
假设订单表按月份分 24 个分区,查询 where create_time >= '2026-07-01' and create_time < '2026-08-01',优化器可以只访问 7 月分区;如果查询 where user_id=1001 且不带时间,可能需要检查多个分区。分区表的收益来自分区裁剪和管理便利,不是自动把单机能力变成 24 台机器。
一台 MySQL 实例:
orders 逻辑表
|- p202601
|- p202602
|- p202603
CPU、内存、I/O 仍主要受这一台实例限制。
二、分区表适合什么问题
分区表常见价值:
- 历史数据按时间分区,归档和删除更方便;
- 查询经常带分区键,可以减少扫描范围;
- 单表数据很大,但还没到必须跨实例扩展;
- 运维上希望按分区管理数据。
它不适合解决所有性能问题。如果 SQL 不带分区键,或者瓶颈是单机 CPU、I/O、连接数,分区表作用有限。
分区表特别适合历史数据生命周期管理。比如日志表每天 500 万行,保留 180 天,如果按天或月分区,删除历史数据可以通过丢弃旧分区完成,比大范围 delete 更轻。查询近 7 天日志时,如果条件带时间,也能裁剪掉旧分区。它解决的是“单实例内更好管理和裁剪”,不是解决跨机器水平扩展。
| 需求 | 分区表是否适合 | 原因 |
|---|---|---|
| 按时间归档删除 | 适合 | 可按分区快速管理历史数据 |
| 查询总带时间范围 | 较适合 | 可做分区裁剪 |
| 单机写入打满 | 不够 | 仍在同一实例内 |
| 跨用户水平扩展 | 不够 | 需要分库分表或分布式方案 |
记忆钩子:分区表像把一个柜子分抽屉,分库分表像把柜子搬到多间房;前者方便管理,后者解决空间和吞吐扩展。
三、分库分表解决的是扩展性
分库分表把数据按 shard key 拆到多个库或表。比如按 user_id 取模,把用户订单分散到 16 张表或多个实例。
好处是容量和写入压力可以水平扩展;代价是应用复杂度上升:
- 查询必须带 shard key 才好路由;
- 跨分片 JOIN 很难;
- 全局唯一 ID 要单独设计;
- 跨分片事务复杂;
- 扩容迁移成本高。
用数字看更直观:单库每秒稳定承载 5000 写入,如果业务增长到每秒 3 万写入,单靠分区表仍然压在同一实例上;分成 8 个库后,理想情况下写入可以分摊到多个实例。但代价是查询必须路由,跨分片聚合和排序会变复杂,事务一致性也更难。
四、什么时候不要急着分库分表
分库分表是架构手术,不是普通 SQL 优化。很多问题先用这些手段解决:
- 补合适索引;
- 冷热数据归档;
- 读写分离;
- 缓存热点数据;
- 优化 SQL 和分页;
- 使用汇总表或搜索系统。
只有单机容量、写入吞吐、表大小和业务增长趋势确实逼近瓶颈时,再考虑分库分表。
这个判断要基于指标,不要因为“单表 1000 万行”就立刻拆。1000 万行但查询都命中主键和高质量联合索引,可能很稳;500 万行但写入热点集中、无索引大扫描、高并发统计,也可能很糟。先证明瓶颈在哪里,再选择拆分手段。
五、分片键选择很关键
分库分表最怕 shard key 选错。好的分片键应该:
- 高频查询能带上;
- 数据分布均匀;
- 写入不会集中到单个分片;
- 业务边界清晰;
- 后续扩容可迁移。
如果订单按 user_id 分片,查某个用户订单很方便;但按商家聚合、全局时间排序就会变复杂。
分片键一旦选定,后续所有查询都会被它影响。user_id % 16 能均匀分散用户订单,但如果大量查询是按 merchant_id 查订单,就会变成跨 16 个分片汇总。分片键不是单纯看分布均匀,还要看核心查询是否能带上它。
六、分区和分库分表的查询差异
分区表对应用基本透明,SQL 仍写同一张表,优化器负责判断访问哪些分区。分库分表通常需要应用或中间件根据 shard key 路由到具体库表;如果没有 shard key,可能要广播查询所有分片,再合并结果。
分区表查询:
select ... from orders where create_time between ...
MySQL 内部裁剪分区
分库分表查询:
应用/中间件根据 user_id -> 定位 order_03
没有 user_id -> 多分片查询并合并
七、常见误区与追问
- 误区:分区表就是分库分表。 分区表仍在一个 MySQL 实例内,应用感知低;分库分表可跨库跨实例,需要路由和分片治理。
- 误区:分区表能解决单机写入瓶颈。 分区表主要帮助裁剪和管理,CPU、内存、I/O 仍受单实例限制。
- 误区:表大就必须分库分表。 是否拆分要看索引、查询模式、容量、写入吞吐和增长趋势,不能只看行数。
- 误区:分片键只要分布均匀就好。 分片键还必须匹配高频查询,否则大量请求会变成跨分片广播。
- 追问:分区表最适合什么场景? 按时间管理历史数据、查询常带分区键、需要快速归档或删除旧分区的场景。
- 追问:分库分表会带来哪些代价? 跨分片 JOIN、全局排序、分布式事务、全局 ID、扩容迁移和运维复杂度都会上升。
八、加强记忆
分区表是在同一实例内把一张逻辑表拆成多个分区,主要价值是分区裁剪和历史数据管理;分库分表是把数据拆到多个表、多个库甚至多个实例,主要目标是扩展容量和吞吐。能通过索引、归档、缓存、读写分离和汇总表解决的,不要急着做分库分表;真要拆,先选对 shard key,并接受跨分片查询、事务、排序和扩容迁移的复杂度。