开放问答
分区表带非分区键二级索引后 EXPLAIN 的 partition 列为空,分区裁剪为何失效
该问题的正文、回答与评论。
提问者 陈亦舟-362 · 状态 open
MySQLInnoDB分区表EXPLAIN慢查询
背景
MySQL 8.0.32,InnoDB,订单流水表 t_order_flow 约 2.4 亿行,按 created_at 做 RANGE 月分区(约 30 个分区),二级索引 idx_merchant_time (merchant_id, created_at)。业务方反馈「查某商户最近 3 个月订单」慢。
现象
- 慢 SQL:
SELECT id, amount, status FROM t_order_flow WHERE merchant_id = ? AND created_at BETWEEN '2025-04-01' AND '2025-06-30' ORDER BY created_at DESC LIMIT 100,线上 P95 约 4~7s。 EXPLAIN显示type=range, key=idx_merchant_time, rows≈1.8e7,但partition列为空——意味着没有做分区裁剪,扫描了全部分区。- 对照实验:把 WHERE 改成只留
created_at BETWEEN ...(不带 merchant_id),EXPLAIN 立刻显示partition=p7,p8,p9,rows 也降到 2.4e6。说明分区裁剪本身是工作的,但加上merchant_id条件后 partition 列就空了。
已尝试的排查
ANALYZE TABLE t_order_flow后重跑 EXPLAIN,partition 列依旧为空;- 把
created_at范围从 3 个月缩到 1 个月、再缩到 1 天,partition 列始终为空; - 试过
FORCE INDEX (idx_merchant_time),没有变化; - 怀疑是优化器成本估算问题,但
optimizer_trace里considered_execution_plans没看到分区裁剪被显式 skip 的痕迹(trace 太长没贴全)。
期望得到的答案形态
- 为什么「带 merchant_id 后 partition 列就空」?是优化器在 range 扫描与分区裁剪之间做了某种取舍,还是 EXPLAIN 的 partition 列显示逻辑本身有坑(比如走了非分区键索引就不标 partition)?
- 有没有一个稳定的判断方法,能区分「真的没裁剪」和「裁剪了但 EXPLAIN 没标」?(比如 performance_schema / information_schema 里具体的表项或事件)
- 在不改表结构、不加新索引的前提下,有没有写法或参数能让分区裁剪稳定生效?
已采纳
回答者
回答正文
评论
暂无评论。