MySQL范围分区必须用PARTITION BY RANGE,按列值连续区间切分数据,分区列须为单列且参与主键/唯一索引,VALUES LESS THAN须严格递增并以MAXVALUE收尾,推荐用TO_DAYS()处理时间字段。
MySQL 范围分区(RANGE)必须用 PARTITION BY RANGE,不是 BY HASH 或 BY LIST
范围分区的核心是按列值的连续区间切分数据,比如按时间、id、金额。如果误用了 partition by hash,哪怕逻辑上想“按月”,也得不到可预测的物理分布——hash 会打散值,无法实现「查某个月只扫一个分区」的效果。
常见错误现象:EXPLAIN PARTITIONS SELECT * FROM orders WHERE order_date = '2024-03-15' 显示扫描全部分区,说明分区键没对齐或类型不匹配。
-
PARTITION BY RANGE后面的表达式必须是单列,且该列不能是TEXT、BLOB或其他不可比较类型 - 分区列必须是主键/唯一索引的一部分(否则建表报错:
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function) - 每个
VALUES LESS THAN必须严格递增,且最后一个分区通常要用MAXVALUE收尾,否则插入超出范围的值会失败
时间字段做 RANGE 分区时,别直接用 DATETIME,优先转成 INT 或用 TO_DAYS()
用 DATETIME 列直接分区看着直观,但 MySQL 不支持在 PARTITION BY RANGE 中直接调用函数(如 YEAR(order_date)),除非用 GENERATED COLUMN;而 TO_DAYS(order_date) 是少数被允许的内置函数之一,兼容性好、计算快。
使用场景:日志表、订单表按天/月归档,需要高频按时间范围查询或定期 DROP PARTITION。
- 推荐写法:
PARTITION BY RANGE (TO_DAYS(order_date)),配合VALUES LESS THAN (TO_DAYS('2024-04-01')) - 避免写
PARTITION BY RANGE (order_date)—— 这要求order_date是DATE类型,且值必须精确到日,DATETIME会因时分秒导致分区边界失效 - 如果用
INT存时间戳(如created_at_int),分区更稳定,但需业务层保证写入值正确,且注意时区一致性
新增分区不能用 ALTER TABLE ... ADD PARTITION 填空,必须接在最大值之后
范围分区的结构是线性的,MySQL 不允许在已有分区中间插入新分区(比如已有 P1(ERROR 1481 (HY000): Invalid partition name 或更隐晦的 out of range 提示。
性能影响:每次 ADD PARTITION 都要重写元数据,但不移动数据;但如果漏掉 MAXVALUE 分区,后续插入超界数据直接失败,比性能问题更致命。
- 正确操作顺序:先确认当前最大
VALUES LESS THAN值 → 新分区从该值开始 → 末尾仍保留P_max VALUES LESS THAN MAXVALUE - 示例:当前最后分区是
P202403 VALUES LESS THAN (TO_DAYS('2024-04-01')),下个应建P202404 VALUES LESS THAN (TO_DAYS('2024-05-01')) - 别依赖自动化脚本 blindly add,务必检查
INFORMATION_SCHEMA.PARTITIONS中的TABLE_ROWS和PARTITION_DESCRIPTION
查询不走分区剪枝?重点查三件事:分区键是否参与 WHERE 条件、类型是否一致、是否用了函数包裹
分区剪枝(partition pruning)失效是最常见的性能陷阱。表面看写了 WHERE order_date BETWEEN '2024-03-01' AND '2024-03-31',但执行计划仍扫全表分区,大概率是下面某个环节断了。
- WHERE 中的列名必须和
PARTITION BY RANGE的表达式完全一致(比如建表用TO_DAYS(created_at),就不能在查询里写WHERE DATE(created_at) = '2024-03-01') - 字符串和数值类型混用:传入
'2024-03-01'给TO_DAYS()没问题,但若分区键是INT,而 WHERE 里写WHERE part_key = '20240301'(带引号),可能触发隐式转换,剪枝失效 - 涉及多表 JOIN 时,只有驱动表的分区键条件能触发剪枝;被驱动表即使有分区,也可能全扫
真正麻烦的是那种“看起来应该剪枝却没剪”的情况——往往卡在类型隐式转换或表达式等价性判断上,这时候得盯死 EXPLAIN PARTITIONS 输出里的 partitions 列,而不是只看 type 或 rows。

















