分区裁剪仅在WHERE条件能静态推导出确定分区范围时生效,如partition_column = 127、IN或BETWEEN等明确约束;函数包裹、子查询、隐式转换或非等值条件(HASH分区)均导致失效,必须通过EXPLAIN的partitions列验证。

分区裁剪只在 WHERE 条件能推导出确定分区范围时生效
MySQL 的分区裁剪不是“智能猜测”,而是严格依赖优化器能否将 WHERE 条件简化为对分区键的明确约束。只要条件无法静态评估出分区边界,裁剪就完全失效,退化为全分区扫描。
常见有效形式包括:
-
partition_column = 127→ 精确命中单个分区(如p1) -
partition_column IN (126, 127, 128)→ 映射到多个但有限的分区(如p1,p2) -
partition_column BETWEEN 126 AND 129→ 范围可被转换为等效IN列表 partition_column > 125 AND partition_column → 同样可被重写为离散值集合
但以下写法会直接禁用裁剪:
-
region_code + 1 > 126(表达式干扰了分区键的裸露使用) -
region_code IN (SELECT region_code FROM config)(子查询结果不可静态推断) -
region_code LIKE '12%'(字符串匹配无法映射到 RANGE 分区逻辑)
EXPLAIN 的 partitions 列是唯一可信依据
不要靠“感觉”或执行时间判断是否裁剪成功。必须查 EXPLAIN 输出中的 partitions 字段——它明确列出实际参与扫描的分区名。
例如:
mysql> EXPLAIN SELECT * FROM t_range WHERE price > 18 AND price < 23; +----+-------------+---------+------------+------+ | id | select_type | table | partitions | type | +----+-------------+---------+------------+------+ | 1 | SIMPLE | t_range | p1,p2 | ALL | +----+-------------+---------+------------+------+
如果这里显示的是 p0,p1,p2,p3 或 NULL,说明裁剪失败。注意:partitions 为 NULL 表示该表未分区,或语句根本没走分区逻辑(比如用了函数包装分区键)。
RANGE/LIST 分区支持范围裁剪,HASH/KEY 只支持等值裁剪
分区类型决定了裁剪能力上限:
-
RANGE和LIST分区:支持>、<、BETWEEN、IN等多种条件,因为其分区边界是显式、有序的 -
HASH和KEY分区:仅支持=和IN;region_code > 100这类条件永远无法裁剪,因为哈希值无序,无法反推哪些桶可能含目标值
一个典型陷阱是:用 TO_DAYS(dob) 做 RANGE 分区键没问题,但若改用 HASH(TO_DAYS(dob)),所有范围类查询都会失去裁剪能力。
分区键必须出现在 WHERE 中,且不能被函数包裹
裁剪的前提是优化器能“看到”原始分区键值。任何封装都会切断这个链路:
- ✅
WHERE region_code = 127→ 裁剪生效 - ❌
WHERE ABS(region_code) = 127→ 失效(ABS()阻断识别) - ❌
WHERE region_code + 0 = 127→ 失效(隐式类型转换或计算干扰) - ❌
WHERE region_code IN (SELECT ?)→ 失效(参数绑定不改变本质,但预编译阶段无法展开)
即使是看似无害的 CAST(region_code AS UNSIGNED),也会让裁剪掉线——MySQL 不会对分区键做任何函数推导,只认裸列名 + 简单比较操作符。
真正容易被忽略的一点:裁剪发生在优化器阶段,与索引无关。即使你在非分区键上建了二级索引,只要 WHERE 条件没覆盖分区键,依然要扫所有分区。分区裁剪和索引下推是两套独立机制,不能互相替代。


















