如何分析分区剪裁Partition Pruning是否生效_执行计划中的Pstart与Pstop解读

2次阅读

Pstart和Pstop是优化器决定访问的物理分区编号范围,若二者相等且对应目标分区编号则裁剪生效,若Pstart=1、Pstop=N则全分区扫描;需结合SHOW CREATE table确认编号映射,并避免对分区键使用函数。

怎么看 EXPLAIN 里的 PstartPstop 是否合理

分区裁剪是否生效,最直接的证据就藏在 explain 输出的执行计划中——特别是 pstart(partition start)和 pstop(partition stop)两列。它们不是“扫描起止时间”,而是优化器决定访问的**物理分区编号范围**。

比如你建了按年分区的表,共 4 个分区:p2021p2022p2023p2024,对应内部编号可能是 1~4。当你查 2023 年数据时,理想输出是:

| id | select_type | table   | partitions | Pstart | Pstop | ... | |----|-------------|---------|------------|--------|--------|-----| |  1 | SIMPLE      | orders  | p2023      |      3 |      3 | ... |

这说明只访问第 3 号分区(即 p2023)。如果看到 Pstart=1Pstop=4,就是全分区扫描,裁剪失败。

  • PstartPstop 是整数索引,不是分区名;要对照 SHOW CREATE TABLEINformatION_SCHEMA.PARTITIONS 查编号映射
  • mysql 5.7+ 默认在 EXPLAIN FORMAT=TREE 中不显示这两列,必须用 EXPLAIN FORMAT=TRADITIONAL 或老式文本格式
  • partitions 列为空或显示 NULL,大概率裁剪没触发,别信 rows 估算值

为什么 WHERE 条件写了分区键,Pstart/Pstop 还是全量?

写对了字段名、也用了等值条件,但 Pstart=1Pstop=N,常见原因不是语法错,而是语义“不可推导”。

  • 分区键被函数包裹:WHERE YEAR(order_date) = 2023 → 优化器无法反推日期范围,裁剪失效;应改用 order_date >= '2023-01-01' AND order_date
  • 隐式类型转换dtString 分区列,却写 WHERE dt = 20230101 → MySQL 会把分区值转成数字比较,破坏分区元数据匹配
  • 使用了非确定性函数:WHERE dt = CURDATE()dt = DATE_SUB(NOW(), INTERVAL 1 DAY),部分版本(如 MySQL 8.0.33 前)不支持运行时裁剪,Pstart/Pstop 仍为全量
  • 分区表达式与查询条件不一致:比如按 TO_DAYS(order_date) 分区,但 WHERE 里用的是 order_date >= '2023-01-01' —— 看似合理,实际依赖优化器能否将常量日期准确映射到 TO_DAYS 值,有版本兼容风险

EXPLAIN PARTITIONS 和普通 EXPLAIN 的关键区别

MySQL 中只有显式加上 PARTITIONS 关键字,才会在执行计划中输出 partitionsPstartPstop 这些列。漏掉这个关键词,等于关掉了分区裁剪的“诊断开关”。

  • 错误写法:EXPLAIN SELECT * FROM orders WHERE order_date >= '2023-01-01'; → 不显示分区信息
  • 正确写法:EXPLAIN PARTITIONS SELECT * FROM orders WHERE order_date >= '2023-01-01'; → 显示 partitions 列及 Pstart/Pstop
  • 注意:EXPLAIN FORMAT=TREE 不支持 PARTITIONS,二者互斥;需要看裁剪,就老实用传统格式
  • 在慢查询日志或 Performance Schema 中,EXPLAIN 记录默认不含分区信息,必须主动补上 PARTITIONS 才能归因

除了 Pstart/Pstop,还有哪些信号说明裁剪可能假阳性

有时 Pstart=Pstop 看着很完美,但实际性能没提升,甚至更差——说明裁剪“形式上成功”,但底层没省 IO。

  • 分区本身为空:Pstart=Pstop=3,但 p2023 是空分区,扫描开销极小,容易误判为“裁剪有效”
  • 分区数据极度倾斜:比如 p2023 存了全表 95% 的数据,虽然只扫一个分区,IO 量并没降多少
  • 用了全局二级索引(GSI):MySQL 8.0+ 支持全局索引,但裁剪逻辑可能绕过分区判断,导致 Pstart/Pstop 正常,实际仍走索引全扫
  • 查询含 FORCE INDEX:人为指定索引可能干扰优化器对分区的决策路径,使 Pstart/Pstop 失真

真正可靠的验证方式,是结合 Handler_read_* 状态变量(如 Handler_read_next)或磁盘 IO 监控,看实际读取的数据页是否与目标分区规模匹配。光盯 Pstart/Pstop 容易被表象骗过去。

text=ZqhQzanResources