从3分钟到0.3秒:DBeaver执行计划实操手册
【免费下载链接】dbeaverFree universal database tool and SQL client项目地址: https://gitcode.com/GitHub_Trending/db/dbeaver
一条平时跑800毫秒的SQL,业务上线让数据量翻倍后,一跑就是3分钟。你盯着转圈的加载图标,只能瞎猜是哪个索引没建上。其实数据库把所有答案都写在执行计划(Execution Plan,即查询执行的详细步骤蓝图)里了。DBeaver执行计划功能把这份蓝图直接渲染成可视化的计划树。这篇带你一步步把它读出来、用来看病。
30秒生成第一张执行计划
生成执行计划的最快路径:打开SQL Editor,选中要分析的查询,按Alt+X,或者点工具栏的Explain Plan按钮,结果区就会弹出计划树。不需要手敲EXPLAIN语句,DBeaver替你向数据库发了请求,并负责解析返回结果。
完整操作就三步:
- 确认已打开数据库连接(MySQL、PostgreSQL等均可)
- 在SQL Editor中选中要分析的那条语句
- 按Alt+X,结果区即显示计划树
没选中文字时,DBeaver会默认分析光标所在的那条语句。这个解释入口的代码在 SQLEditor.java,想确认行为可以去翻。
🔍 读懂计划树:5个必看节点
先认脸。任何数据库的计划树,拆开看基本就是下面五类节点:
| 节点类型 | 长什么样 | 看到它意味着什么 | 要不要警惕 |
|---|---|---|---|
| Scan | Seq Scan on orders、Index Scan | 数据怎么从表里读出来 | 全表扫描且行数大时警惕 |
| Join | Hash Join、Nested Loop | 多表怎么连接 | Nested Loop且两侧行数都大,必须警惕 |
| Aggregate | Group Aggregate、HashAggregate | 在做GROUP BY或DISTINCT | 输入行数太大时留意内存 |
| Sort | Sort | 在做ORDER BY排序 | 排序列没走索引时考虑加索引 |
| Materialize | Materialize | 把中间结果存进内存反复用 | 频繁出现时检查子查询是否在重复执行 |
读法一句话:从叶子节点往上读。叶子是Scan,告诉你数据从哪来;越往上的节点,说明数据被加工到什么程度。哪里估算行数最大、成本最高,就先怀疑哪里。
⚡ 慢查询诊断:从计划树里找"病根"
诊断一条慢查询,三步走:先看行数,再看Join,最后看索引列。下面这条订单报表SQL就是典型翻车款:
SELECT o.order_id, SUM(oi.amount) FROM orders o JOIN order_items oi ON o.id = oi.order_id WHERE o.create_time > '2023-01-01' AND DATE(oi.update_time) = '2023-06-01' GROUP BY o.order_id;① 哪个节点估算行数爆炸
看每个节点上的估算行数(Rows)。口诀:你看到某个Scan节点行数上百万,就去检查它的过滤条件到底筛掉了多少数据。比如上面例子里orders走了条件之后行数只降了一点点,说明过滤基本没生效。
② Join是否退化成了Nested Loop
你看到Join节点标着Nested Loop,就检查它两个子节点各自的估算行数。外层100万行、内层每轮被探一次,那就是天文数字次探测。这种组合下,只要内表有合适索引,优化器一般会换Hash Join。
③ 索引列是否被函数"包"住了
你看到索引列外面套了函数,比如DATE(oi.update_time),就去检查该列上建的索引。说白了,B-tree索引按原始值排序,列被函数包了一层就对不上了,只能全表扫。把条件改写成范围查询:oi.update_time >= '2023-06-01' AND oi.update_time < '2023-06-02',索引立刻能上。
改完两处再按一次Alt+X:orders换成了Index Scan,条件改范围后order_items也走了索引,3分钟回到0.3秒。
主流数据库的适配差异
不同数据库拿计划的方式不一样,DBeaver里的行为也有区别,对比如下:
| 数据库 | 获取方式 | DBeaver里的特殊行为 |
|---|---|---|
| MySQL | EXPLAIN FORMAT=JSON | 专门解析JSON转成树,显示估算行数和索引信息 |
| PostgreSQL | EXPLAIN,可带XML格式 | 支持VERBOSE输出,也能加载已保存的计划文件再展示 |
| OceanBase | 返回JSON格式计划 | 用独立的JSON分析器解析成计划树 |
| Altibase | 反射调用驱动特定方法取计划文本 | 拿到文本后交给内置解析器构建树 |
各数据库的解析器代码就在各自的ext插件里,MySQL的在 MySQLPlanJSON.java。想知道你当前连接走的是哪个解析器,对号入座看对应插件就行。
这些坑我帮你踩过了
- 计划生成超时:按Alt+X后转圈一分钟出不来。原因是查询本身太重,优化器估算统计信息也卡住。处理办法是把查询拆成片段逐段解释,或者先用LIMIT缩小数据范围再解释。
- 权限不足:状态栏报权限类错误,计划显示不出来。原因是当前账号对涉及的表没有查询权限。处理办法是找DBA开只读分析账号,别急着要全量权限。
- 视图导致计划截断:树停在视图那一层,看不到底层表的Scan。原因是部分数据库的EXPLAIN默认不展开视图内部。处理办法是把查询改写为直接引用基表后再解释,或者单独解释基表。
- 只读账号看不到Cost:节点上只有行数没有成本。原因是数据库本身只返回运行统计,或当前账号读不到统计信息表。处理办法是按行数与节点类型来判断瓶颈,别死磕成本数字。
接下来往哪走
路线一共三个阶段:
- 阶段一:能看懂节点——五类节点背熟,拿到任何计划树都能一句话说清它在干什么
- 阶段二:能改索引/改写SQL——看到全表扫描和Nested Loop,知道加哪个索引、怎么改写条件
- 阶段三:能影响优化器——用各数据库的Hint或参数调整,把执行路径引导到你想要的那条
下次那条800毫秒的SQL再变成3分钟时,先别慌着加索引。按Alt+X,看计划树里到底哪变了。
【免费下载链接】dbeaverFree universal database tool and SQL client项目地址: https://gitcode.com/GitHub_Trending/db/dbeaver
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考