分区表非性能银弹,仅当单表超千万行且存在高频时间范围查询或需按月/年归档时才适用;否则应优先优化索引,避免因误用导致全分区扫描或写入性能下降。

分区表不是性能银弹,用错分区键或类型反而会让查询变慢,甚至拖垮整个表的维护效率。
什么时候该考虑分区表而不是加索引?
当单表行数超过千万、且存在明确的高频时间范围过滤(比如 WHERE create_time BETWEEN '2025-01-01' AND '2025-06-30'),或者需要按月/年快速归档删除旧数据时,分区才真正有用。单纯因为“表大”就分区,大概率白忙活。
- 索引能解决的范围扫描问题,优先调优索引和执行计划,别急着上分区
- 如果查询条件几乎不带分区键(比如只查
user_id但按create_time分区),MySQL无法裁剪,会扫全分区,性能比非分区表还差 - 写入压力大的场景慎用:每个分区都有独立的锁和元数据开销,
INSERT频繁时可能比单表更卡
PARTITION BY RANGE 怎么写才不踩坑?
这是最常用也最容易写错的类型。核心是:分区表达式必须是单调、确定、可比较的,不能依赖运行时函数或非确定性计算。
- ✅ 正确:
PARTITION BY RANGE (TO_DAYS(create_time))或PARTITION BY RANGE (YEAR(create_time)) - ❌ 错误:
PARTITION BY RANGE (DATE_FORMAT(create_time, '%Y%m'))——DATE_FORMAT返回字符串,排序行为不可靠,可能导致分区裁剪失效 - ❌ 错误:
PARTITION BY RANGE (UNIX_TIMESTAMP(create_time))—— 虽然能用,但跨时区易出错,且 MySQL 8.0+ 对高精度时间戳分区支持不稳定 - 务必预留
VALUES LESS THAN (MAXVALUE)分区兜底,否则插入超出范围的数据会直接报错ERROR 1526 (HY000): Table has no partition for value
分区数量多少算合理?
没有固定数字,但几十个是常见安全区间;超过 100 个分区就要警惕元数据膨胀和管理成本。
- 按月分区:最多建议覆盖 3–5 年,即 36–60 个分区。再多会导致
INFORMATION_SCHEMA.PARTITIONS查询变慢,影响 DDL 和统计信息收集 - 按天分区:仅适用于日均写入量极大(百万级+)、且必须按天归档的场景,否则分区数增长太快,运维负担重
- 不要为“未来三年”一次性建好所有分区——提前建 2–3 个够用就行,用存储过程+事件调度器动态添加,避免高峰期阻塞
- 删除旧分区用
ALTER TABLE DROP PARTITION,比DELETE FROM ... WHERE create_time 快几个数量级,但要注意它会触发全局锁,得在低峰期执行
为什么 EXPLAIN PARTITIONS 显示没走分区裁剪?
这是最常被忽略的问题:你以为条件命中了分区键,其实 MySQL 没识别出来。
- 检查 WHERE 条件是否直接使用分区键列,而非其表达式——比如分区键是
create_time,但你写了WHERE DATE(create_time) = '2025-06-01',这就废了裁剪 - 确认字段类型和分区表达式类型一致:如果分区用
TO_DAYS(create_time),那WHERE TO_DAYS(create_time) = 739780才有效;用字符串或浮点数比较会失败 - 联合索引里包含分区键 ≠ 分区裁剪生效——裁剪只看 WHERE 中是否显式、确定地约束了分区键本身
- 用
EXPLAIN PARTITIONS看输出里的partitions列,如果是all或列出全部分区名,说明没裁剪;只出现 1–2 个分区名才是正常
分区表真正的复杂点不在创建,而在长期演进:业务逻辑变化后,原分区键可能不再高频使用,而重建分区代价极高。上线前必须确认未来 2–3 年的查询模式不会根本性偏移,否则不如一开始就用分库分表或归档冷数据到其他系统。



















