← Back to skills
extension
Category: Development & EngineeringAPI key requirement unconfirmed

SQL 执行计划诊断

把 MySQL / OceanBase / seekdb 的 EXPLAIN 输出,变成 P0/P1/P2 分级的诊断报告(全表扫描、未命中索引、候选索引没用上、filesort、临时表等),每条给「证据 → 动作 → 验证方式」。离线运行、无第三方依赖。

personAuthor: yturytuerhubModelScope

SQL 执行计划诊断(sql-explain-doctor)

把执行计划变成“先修什么、为什么、怎么验证”的三段式结论,避免只丢一句“加索引”。

何时使用

  • 用户提供了 EXPLAIN、EXPLAIN FORMAT=TREE、EXPLAIN ANALYZE 的输出(MySQL 8.x、OceanBase、seekdb)。
  • 用户问:“这条 SQL 为什么慢”“要不要加索引”“为什么没走索引”“这个计划合理吗”。

不适用

  • 只有 SQL 文本、没有执行计划:先请用户执行 EXPLAIN <SQL> 并贴回结果。
  • 需要压测、参数调优、锁等待或资源瓶颈分析:超出本技能范围,说明原因并建议补充的信息。
  • 没有表结构(SHOW CREATE TABLE)与数据量时,不下“必须加索引”的定论,只给候选建议。

工作流程

  1. 判断格式:计划是表格型(含 type / key / rows 列)还是树型(含 OPERATOR / EST.ROWS)。

  2. 跑脚本:把计划原文存成文本文件,执行

    python scripts/explain_report.py --input plan.txt
    

    也可 --input - 从标准输入读,--format json 输出结构化结果。脚本只读、离线、无第三方依赖。

  3. 人工复核:脚本是启发式规则,必须结合 SQL、表数据量、现有索引确认;拿不准的结论标“待确认”,不要直接断言。

  4. 输出报告:结论速览表 + 逐条建议(证据 → 动作 → 验证方式)+ 需要用户补充的信息。

  5. 给出验证路径:EXPLAIN ANALYZE 看真实耗时、SHOW INDEX FROM t 看现有索引、ANALYZE TABLE 更新统计信息。

规则表(脚本内置)

| 规则 | 触发条件 | 优先级 | 建议方向 | | --- | --- | --- | --- | | R01 | type=ALL 且 rows ≥ 1000 | P0 | 全表扫描:为过滤/连接列建索引,或收窄条件 | | R02 | key 为空且 rows ≥ 10000 | P1 | 未命中任何索引:检查条件是否可索引、是否发生隐式转换 | | R03 | possible_keys 非空但 key 为空 | P1 | 有候选索引没用上:看选择性、函数包裹、最左前缀 | | R04 | 多表连接中 ≥ 2 个表 type=ALL | P1 | 被驱动表缺索引,或连接顺序需要调整 | | R05 | rows ≥ 100000 | P1 | 扫描行数过大:先过滤再连接,避免全量聚合 | | R06 | Extra 含 Using filesort | P2 | 排序无法用索引:考虑 (过滤列, 排序列) 联合索引 | | R07 | Extra 含 Using temporary | P2 | 临时表:常见于 GROUP BY / DISTINCT / UNION,考虑覆盖索引 | | R08 | type=index | P2 | 全索引扫描:确认是否真的需要遍历整棵索引 | | R09 | filtered < 10 且 rows ≥ 10000 | P2 | 过滤性差:索引选择性不足,考虑联合索引或改写 | | T01 | 树型计划中 TABLE SCAN 且估算行数 ≥ 10000 | P1 | 大表全扫描:同 R01 | | T02 | 树型计划中出现 TEMP TABLE / SORT | P2 | 排序或临时表算子:同 R06 / R07 | | T03 | 树型计划中 NESTED LOOP 与 TABLE SCAN 同时出现 | P1 | 嵌套循环内层全扫描:内层连接列建索引 |

输出格式

# EXPLAIN 诊断报告
- 输入格式:表格型 / 树型
- 计划条目:N 条
- 命中规则:R01、R05 ...

## 结论速览
| 优先级 | 规则 | 问题 | 位置 | 依据 |

## 逐条建议
### P0 · R01 全表扫描(表 o)
- 证据:type=ALL,rows=980000
- 动作:为 o.user_id 建索引 / 改写为按时间范围过滤
- 验证:再次 EXPLAIN,确认 type 变为 range 或 ref

## 需要补充的信息
- 表结构与现有索引(SHOW CREATE TABLE)
- 真实耗时(EXPLAIN ANALYZE)

示例

python scripts/explain_report.py --input examples/sample_explain.txt

样例计划与期望报告见 examples/。

质量检查

  • [ ] 每条结论都能指回计划里的某一行、某一列
  • [ ] 区分“计划显示的事实”与“我的推测”,推测标注待确认
  • [ ] 索引建议写明列顺序与理由,并提示评估写入放大
  • [ ] 不承诺具体提速倍数,改用“预期减少扫描行数”这类可验证表述
<!-- OB-S:5N4ExJh4DqZMK7EZYZXlzQ -->