分区和分表有什么区别?
结论:分区(Partition)是数据库内核把一张逻辑表的数据按规则分散到多个物理文件,SQL 不变、由优化器做分区裁剪(Partition Pruning);分表(Sharding)是应用层或中间件把一张表拆成多张独立表,SQL 必须按规则改写。分区不跨实例,突破不了单机上限;分表可以跨库,但要自己承担路由与归并。
一、对比表
| 维度 | 分区(Partition) | 分表(Sharding) |
|---|---|---|
| 执行者 | 数据库内核 | 应用或中间件 |
| SQL 是否改写 | 否 | 是(库名、表名) |
| 是否跨实例 | 否,仍是单库单机 | 可以,分库即跨实例 |
| 事务 | 单机本地事务 | 跨库需分布式事务 |
| 索引 | 每个分区独立索引,全局唯一索引受限 | 每表独立,天然无全局约束 |
| 运维 | 一条 ALTER 管全部分区 | 需逐表变更 |
| 扩容 | 受单机资源限制 | 可加机器线性扩展 |
| 典型用途 | 按时间归档、快速清理 | 海量数据、高并发写入 |
二、分区的工作方式
t_order(逻辑上一张表)
┌──────────┬──────────┬──────────┬──────────┐
│ p2025q1 │ p2025q2 │ p2025q3 │ pmax │
│ 独立 ibd │ 独立 ibd │ 独立 ibd │ 兜底 │
└──────────┴──────────┴──────────┴──────────┘
WHERE create_time >= '2025-07-01'
└── 优化器裁剪:只扫 p2025q3 与 pmax
MySQL 支持 RANGE、LIST、HASH、KEY 四类分区;8.0 起支持 RANGE COLUMNS 直接用日期或字符串列做分区键。
三、建表与配置
CREATE TABLE t_order (
id BIGINT UNSIGNED NOT NULL,
user_id BIGINT UNSIGNED NOT NULL,
amount DECIMAL(12,2) NOT NULL,
create_time DATETIME NOT NULL,
PRIMARY KEY (id, create_time) -- 分区键必须包含在每个唯一键中
) ENGINE=InnoDB
PARTITION BY RANGE COLUMNS (create_time) (
PARTITION p2025q1 VALUES LESS THAN ('2025-04-01'),
PARTITION p2025q2 VALUES LESS THAN ('2025-07-01'),
PARTITION p2025q3 VALUES LESS THAN ('2025-10-01'),
PARTITION pmax VALUES LESS THAN (MAXVALUE)
);
-- 清理历史数据:秒级完成,不产生大事务,不锁全表
ALTER TABLE t_order DROP PARTITION p2025q1;
-- 查看裁剪效果
EXPLAIN SELECT * FROM t_order WHERE create_time >= '2025-08-01' AND create_time < '2025-09-01';
-- partitions 列会显示 p2025q3,而不是全部
关键限制:分区键必须出现在表的所有唯一索引(含主键)里,否则建表直接报错——这就是分区表主键常写成 (id, create_time) 的原因。
四、常见追问
Q1:分区能提升并发吗? 基本不能。所有分区共享同一个实例的缓冲池(Buffer Pool)、redo log 与连接数,锁和 IO 仍是单机资源。只有在查询条件里带上分区键触发裁剪,才能减少扫描量。
Q2:为什么大厂很少用分区表? 一是运维工具链对分区的支持参差,二是分区键一旦选错无法在线修改,三是跨分区查询容易退化为全表扫描。分表的路由完全在应用掌控之内,更灵活也更好排查。
Q3:分区和分表能一起用吗?
可以。实践中常见「先按业务分库分表,再在每个物理表上按时间分区」,用 DROP PARTITION 低成本归档冷数据。
Q4:分区表的主键自增还有效吗? 有效,但自增只在单实例内唯一,跨分表就不再全局唯一,需要改用全局 ID 方案。
Q5:分区表一定比普通表快吗? 不一定。只有查询条件命中分区键、触发裁剪时才快;不带分区键的查询会扫描所有分区再合并结果,反而比单表更慢。
所以分区键的选择标准与分片键一致:查询必带、分布均匀、上线后不可变。
小结
- 分区是内核行为,SQL 透明、不跨机;分表是架构行为,SQL 需改写、可跨库。
- 需要突破单机上限就分表;只需要按时间归档清理,分区更省事。
- 分区键必须进入所有唯一索引,这是建表时最容易踩的坑。