文章目录
- 前言
-
- [一、DBeaver 执行计划长什么样](#一、DBeaver 执行计划长什么样)
- 二、核心列的含义
-
- [1. `Operation` --- 做了什么操作](#1.
Operation— 做了什么操作) - [2. `Object` --- 操作的对象](#2.
Object— 操作的对象) - [3. `Rows` --- 预估扫描行数(最关键!)](#3.
Rows— 预估扫描行数(最关键!)) - [4. `Cost` --- 成本估算](#4.
Cost— 成本估算)
- [1. `Operation` --- 做了什么操作](#1.
- 三、用您的项目举例
- [四、如何快速判断 SQL 好坏](#四、如何快速判断 SQL 好坏)
- 五、实战:拿到执行计划后的排查步骤
- [六、DBeaver 中的快捷操作](#六、DBeaver 中的快捷操作)
- 七、一句话记忆
前言
解释 DBeaver 的执行计划怎么看。
一、DBeaver 执行计划长什么样
在 DBeaver 中选中 SQL → 右键 → Explain Plan,会看到这样的表格:
| Operation | Object | Rows | Cost | Node Type |
|---|---|---|---|---|
| -> Nested Loop Left Join | 100 | 1000 | ||
| -> Index Range Scan | act_ru_task | 50 | 50 | |
| -> Index Lookup | act_ru_variable | 1 | 5 | |
| -> Using temporary | 100000 | 50000 | ||
| -> Table Scan (Full) | act_hi_varinst | 100000 | 30000 |
二、核心列的含义
1. Operation --- 做了什么操作
| 操作名 | 含义 | 好/坏 | 出现场景 |
|---|---|---|---|
| Table Scan (Full) | 全表扫描,一行一行读 | ❌ 最慢 | 没索引或索引没命中 |
| Index Range Scan | 走索引,只扫描一段 | ✅ 快 | WHERE 条件走了索引 |
| Index Lookup | 通过索引找到具体行 | ✅ 最快 | 精准查找 |
| Using temporary | 用了临时表(内存或磁盘) | ⚠️ 小心 | GROUP BY、行转列 |
| Using filesort | 用文件排序 | ⚠️ 小心 | ORDER BY 没走索引 |
| Nested Loop Join | 嵌套循环关联 | ⚠️ | JOIN 两张大表时慢 |
| Hash Join | 哈希关联 | ✅ | 大表 JOIN 时高效 |
| Using index | 只用索引,不用查表 | ✅✅ 最快 | 覆盖索引 |
| Using where | 过滤数据 | 正常 | WHERE 条件 |
2. Object --- 操作的对象
就是表名或索引名,比如 act_ru_task、act_hi_varinst。
3. Rows --- 预估扫描行数(最关键!)
| Rows 值 | 含义 | 判断 |
|---|---|---|
| 50 | 扫描 50 行 | ✅ 很快 |
| 10000 | 扫描 1 万行 | ⚠️ 有点慢 |
| 100000 | 扫描 10 万行 | ❌ 慢 |
| 1000000+ | 扫描百万行 | ❌❌❌ 非常慢 |
看执行计划第一眼就看 Rows!Rows 大的地方就是慢的原因。
4. Cost --- 成本估算
MySQL 内部算的一个值,数字越大越慢。一般不用太关注,看 Rows 更直观。
三、用您的项目举例
优化前的执行计划(模拟)
js
Operation | Object | Rows | 解读
------------------------------|------------------|--------|-----------------
Table Scan (Full) | act_hi_varinst | 100000 | ❌ 全表扫10万行
Group By | | 100000 | ❌ 分组也是10万行
Nested Loop Left Join | | 100000 |
Table Scan (Full) | act_ru_task | 5000 |
Subquery (repeat 8x) | same as above | 100000 | ❌ 重复8次!
总扫描行数 ≈ 100000 × 8 = 800000 行
一眼看出问题:
Table Scan (Full)--- 全表扫描,没走索引Rows = 100000--- 扫描量大- 同一个操作重复 8 次
优化后的执行计划(模拟)
js
Operation | Object | Rows | 解读
------------------------------|------------------|--------|-----------------
CTE user_proc_inst: | | |
Index Range Scan | act_ru_task | 100 | ✅ 走索引,只查100行
Union | | 50 |
Index Range Scan | act_hi_taskinst | 50 | ✅
CTE flowable_vars: | | |
Index Range Scan | act_hi_varinst | 1000 | ✅ 走索引,只查1000行
Group By | | 1000 | 只对1000行分组
CTE approval_users: | | |
Index Range Scan | ACT_RU_TASK | 100 | ✅
Main Query: | | |
Nested Loop Join | | 100 |
Index Range Scan | act_ru_task | 50 | ✅
总扫描行数 ≈ 100 + 1000 + 100 + 50 = 1250 行
一眼看出变好的地方:
Table Scan (Full)→Index Range Scan(全表扫描变索引扫描)Rows = 100000→Rows = 1000(扫描量降为 1/100)
四、如何快速判断 SQL 好坏
第一眼看什么?
| 顺序 | 看什么 | 坏的信号 | 好的信号 |
|---|---|---|---|
| ① | Rows 最大的那行 |
几万+ | 几百 |
| ② | type / Operation |
ALL(全表扫描) |
range, ref, const |
| ③ | Extra |
Using temporary, Using filesort |
Using index |
| ④ | 有没有重复的操作 | 同一个表出现多次全表扫描 | 只有一次 |
一个简单的评分标准
js
Rows 10万+ + Full Scan = ❌❌❌ 必须优化
Rows 1万+ + Full Scan = ❌❌ 需要优化
Rows 1000+ + Range Scan = ⚠️ 可以看看
Rows 100以下 + Index Lookup = ✅ 很好
五、实战:拿到执行计划后的排查步骤
js
第1步:找到 Rows 最大的行
└─ Rows = 100000 → 瓶颈在这
第2步:看这行的 Operation
└─ Table Scan (Full) → 全表扫描,没索引
└─ 或是重复出现多次 → 用 CTE 优化
第3步:问为什么 Rows 这么大
└─ 没加 WHERE 条件 → 加条件
└─ WHERE 条件没走索引 → 加索引
└─ 就是要查这么多 → 看能不能分步查
第4步:改完再 EXPLAIN 对比
└─ Rows 从 100000 → 100 ✅ 优化成功
└─ Rows 没变化 → 优化方向不对
六、DBeaver 中的快捷操作
| 操作 | 说明 |
|---|---|
| 选中 SQL → 右键 → Explain Plan | 查看执行计划 |
| 选中 SQL → 右键 → Execute Script (Cmd+Option+X) | 查看实际执行时间 |
| 选中 SQL → 右键 → Execution Plan (Cmd+Shift+E) | 另一种执行计划视图 |
快捷键
| Mac | Windows | 效果 |
|---|---|---|
Cmd + Shift + E |
Ctrl + Shift + E |
查看执行计划 |
Cmd + Option + X |
Ctrl + Alt + X |
执行脚本(看耗时) |
七、一句话记忆
执行计划就是 SQL 的"体检报告",Rows 大的地方就是病灶,Full Scan 就是病名。
- Rows 大 = 体检指标异常(❌)
- Full Scan = 确诊了(没走索引)
- Using temporary = 并发症(用了临时表)
- 改完后 Rows 变小 = 指标恢复正常(✅)