尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Oracle执行计划排查实战:用DBMS_XPLAN配合TaoToken统一Key定位慢SQL

发布时间:2026/9/26 17:27:22

资讯中心
01
ARTICLE

Oracle执行计划排查实战:用DBMS_XPLAN配合TaoToken统一Key定位慢SQL

Oracle执行计划排查实战:用DBMS_XPLAN配合TaoToken统一Key定位慢SQL
1. 慢SQL排查为什么总在“看错计划”上翻车做 Oracle DBA 的朋友大概率都遇到过这种场景业务反馈某条 SQL 突然变慢你连上库explain plan for一跑计划看着挺正常走了索引成本也不高可实际执行就是慢得离谱。问题往往出在你看到的是“解释计划”而不是“真实执行计划”。解释计划是优化器在特定绑定变量、特定统计信息下推导出来的而真实执行计划是游标在共享池里实际跑出来的两者可能因为绑定变量窥探、自适应游标、统计信息过期等原因完全不一样。DBMS_XPLAN这个包就是解决这个问题的核心工具。它不只能看解释计划还能从共享池V$SQL_PLAN、AWR、SQL 调优集、SQL 计划基线里把真实执行计划捞出来。其中DISPLAY_CURSOR是日常排查慢 SQL 用得最多的方法因为它直接读游标缓存能看到A-Rows、A-Time、Buffers这些运行时统计一眼就能判断优化器估算和实际差了多少。这篇内容聚焦一个完整闭环从共享池抓真实计划用DBMS_XPLAN.DISPLAY_CURSOR格式化输出识别全表扫描和谓词过滤异常再通过 TaoToken 统一 Key 把执行计划文本交给 AI 辅助解读快速定位瓶颈。适合有一定 SQL 基础、想系统掌握执行计划采集与分析的 DBA 和开发。下面所有脚本都可以直接复制到 SQL*Plus 或 SQL Developer 里跑。2. 前置准备TaoToken 统一 Key 与 API 通道排查慢 SQL 时执行计划文本动辄几十上百行人工逐行比对E-Rows和A-Rows很费眼。我的做法是把计划文本丢给 AI 做初步解读让它标出估算偏差大的步骤和可疑的全表扫描。这里用 TaoToken 的统一 Key 来接入一个 Key 可以走多个模型通道不用为每个模型单独申请。先到官网注册并拿到 Key地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 登录后在控制台创建 API Key控制台入口 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。API 基础地址统一用 https://taotoken.net/api 注意这个地址不带 UTM 参数直接作为base_url使用。如果你只是偶尔解读执行计划用模型对话页面就够了https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。但如果你想把“采集计划 AI 解读”做成脚本自动化那就需要 API Key配合接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 来写调用代码。长期做 SQL 调优、经常跑 Agent 任务的可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 额度更划算。注意TaoToken 在这里的角色是 AI 模型调用的统一入口不涉及数据库连接也不替代任何 Oracle 客户端工具。执行计划采集始终在你的数据库会话里完成。3. 可复制配置从共享池抓真实执行计划3.1 定位 SQL_ID 与 CHILD_NUMBER真实执行计划存在V$SQL和V$SQL_PLAN里前提是游标还在共享池中。先根据 SQL 文本片段找到SQL_ID和CHILD_NUMBERSELECT sql_id, child_number, plan_hash_value, executions, elapsed_time / 1000000 AS elapsed_sec, buffer_gets, disk_reads, sql_text FROM v$sql WHERE sql_text LIKE %你的SQL片段% AND sql_text NOT LIKE %v$sql% ORDER BY last_active_time DESC;这里有个坑sql_text是VARCHAR2(1000)长 SQL 会被截断模糊匹配时尽量用靠前的特征片段。另外一定要加AND sql_text NOT LIKE %v$sql%否则会把查询v$sql本身的语句也捞出来。3.2 用 DISPLAY_CURSOR 输出带运行时统计的计划拿到SQL_ID和CHILD_NUMBER后用DISPLAY_CURSOR输出。关键是format参数日常排查我固定用ALLSTATS LAST它等价于IOSTATS MEMSTATS LAST能带出A-Rows、A-Time、BuffersSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(d86dz1fjtn7g7, 0, ALLSTATS LAST));如果只想看最近一条执行语句的计划两个参数都传NULLSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, ALLSTATS LAST));但要注意ALLSTATS LAST依赖游标执行时收集了运行时统计。如果 SQL 没有加/* gather_plan_statistics */提示也没有开启STATISTICS_LEVELALLA-Rows等列可能为空。所以排查前建议先这样执行一次目标 SQLSELECT /* gather_plan_statistics */ COUNT(*) FROM scott.emp WHERE sal BETWEEN 100 AND 3000;然后再用DISPLAY_CURSOR抓计划统计信息就全了。3.3 format 参数常用组合对照format参数支持用逗号分隔多个关键字也可以用和-增删显示元素。下面这张表是我常用的几组format 写法作用适用场景TYPICAL默认显示基本信息快速看计划结构ALLSTATS LAST带运行时统计只显示最后一次执行慢 SQL 排查首选ALLSTATS ALL带运行时统计累积所有执行分析多次执行的平均表现BASIC PREDICATE精简输出加谓词信息只看过滤条件TYPICAL PARTITION PARALLEL加分区和并行信息分区表、并行查询排查ADVANCED -PROJECTION高级信息去掉列投影减少输出噪音一个实用技巧排查全表扫描时用BASIC PREDICATE ALIAS输出短谓词和别名都在方便快速判断过滤条件是否下推。3.4 从 AWR 抓历史执行计划如果游标已经被挤出共享池DISPLAY_CURSOR就抓不到了这时候要从 AWR 里捞。先查DBA_HIST_SQLSTAT找到SQL_ID和快照区间再用DISPLAY_AWRSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR(d86dz1fjtn7g7, NULL, NULL, ALLSTATS LAST));DISPLAY_AWR的签名和DISPLAY_CURSOR略有不同第二个参数是plan_hash_value第三个是child_number第四个才是format。AWR 里的计划没有A-Rows这种运行时统计但能看到E-Rows和Cost配合DBA_HIST_SQLSTAT里的BUFFER_GETS、DISK_READS也能判断瓶颈。4. 验证请求识别全表扫描与谓词过滤异常4.1 读懂关键列DISPLAY_CURSOR输出里排查慢 SQL 重点盯这几列Id前面带*表示这一步有谓词过滤。Operation是操作类型TABLE ACCESS FULL就是全表扫描。Name是对象名。Starts是这一步执行次数。E-Rows是优化器估算行数A-Rows是实际返回行数这两个差一个数量级以上就要警惕。A-Time是实际耗时Buffers是逻辑读累计值。一个典型异常长这样| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.05 | 1200 | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.05 | 1200 | |* 2 | TABLE ACCESS FULL| EMP | 1 | 13 | 14000 |00:00:00.04 | 1200 |这里E-Rows13A-Rows14000估算偏差超过 1000 倍。优化器以为只返回 13 行实际返回 1.4 万行很可能因此选错了连接方式或扫描方式。谓词部分显示filter(SAL3000 AND SAL100)说明过滤是在全表扫描之后做的没有走索引。4.2 用 TaoToken 辅助解读执行计划把上面这段计划文本复制出来通过 TaoToken 的 API 发给模型让它标出异常点。下面是一个 Python 调用示例base_url用 TaoToken 的 API 地址import requests api_key 你的TaoToken_API_Key base_url https://taotoken.net/api plan_text | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.05 | 1200 | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.05 | 1200 | |* 2 | TABLE ACCESS FULL| EMP | 1 | 13 | 14000 |00:00:00.04 | 1200 | Predicate Information (identified by operation id): 2 - filter((SAL3000 AND SAL100)) prompt f你是Oracle执行计划分析专家。请分析以下执行计划指出 1. 是否存在全表扫描是否合理 2. E-Rows与A-Rows偏差最大的步骤 3. 谓词过滤是否下推 4. 给出优化建议。 执行计划 {plan_text} resp requests.post( f{base_url}/v1/chat/completions, headers{ Authorization: fBearer {api_key}, Content-Type: application/json }, json{ model: claude-sonnet-4-20250514, messages: [{role: user, content: prompt}], temperature: 0.2 }, timeout60 ) print(resp.json()[choices][0][message][content])模型返回的内容通常会指出EMP表走了全表扫描E-Rows与A-Rows偏差 1000 倍以上谓词SAL过滤没有走索引建议在SAL列建索引或检查统计信息是否过期。这样你就不用逐行比对直接拿到可疑点再去验证。4.3 验证优化效果针对上面的问题在SAL列建索引后重新执行并抓计划CREATE INDEX idx_emp_sal ON scott.emp(sal); SELECT /* gather_plan_statistics */ COUNT(*) FROM scott.emp WHERE sal BETWEEN 100 AND 3000; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, ALLSTATS LAST));优化后的计划应该变成INDEX RANGE SCANBuffers从 1200 降到个位数A-Time也会明显下降。如果建了索引还是走全表扫描那就要检查统计信息、绑定变量类型或者是否存在隐式转换。5. 本篇常见错排查5.1 DISPLAY_CURSOR 报 “cannot be found”最常见的原因是SQL_ID或CHILD_NUMBER传错或者游标已经被挤出共享池。先确认V$SQL里还能查到这条 SQLSELECT sql_id, child_number, sql_text FROM v$sql WHERE sql_id d86dz1fjtn7g7;如果查不到说明游标已老化改用DISPLAY_AWR从 AWR 里捞。另外注意SQL_ID前后不要带空格从V$SQL里复制时容易带上不可见字符。5.2 A-Rows 列为空ALLSTATS LAST模式下A-Rows为空说明执行时没有收集运行时统计。解决办法有两个执行 SQL 时加/* gather_plan_statistics */提示或者确认STATISTICS_LEVEL参数SHOW PARAMETER statistics_level;如果是BASIC改成TYPICAL或ALL。生产环境改参数要谨慎优先用提示方式。5.3 计划里出现多个 CHILD_NUMBER同一条 SQL 有多个子游标说明存在绑定变量窥探或自适应游标。逐个查看SELECT child_number, plan_hash_value, executions, buffer_gets, is_bind_sensitive, is_bind_aware FROM v$sql WHERE sql_id d86dz1fjtn7g7;重点看buffer_gets最大的那个子游标那通常是实际执行最慢的计划。is_bind_sensitiveY说明计划对绑定变量敏感可能需要绑定变量窥探或 SQL 计划基线来稳定计划。5.4 谓词信息里出现隐式转换如果Predicate Information里看到TO_NUMBER(COL)或TO_CHAR(COL)说明发生了隐式类型转换索引很可能失效。比如WHERE sal 100这种写法sal是数字列传入字符串会触发转换。改成WHERE sal 100即可。5.5 TaoToken 调用返回 401 或超时401 一般是 Key 没带对检查Authorization头是不是Bearer加 Key中间有空格。超时的话把timeout调大执行计划文本长的时候模型响应会慢一些。如果返回模型不存在确认model字段用的是 TaoToken 支持的模型名具体可以查接入文档。6. 把采集和解读串成日常流程整套流程跑下来核心就三步先用V$SQL定位SQL_ID和CHILD_NUMBER再用DBMS_XPLAN.DISPLAY_CURSOR配合ALLSTATS LAST抓真实计划最后把计划文本通过 TaoToken 统一 Key 交给 AI 标出估算偏差和全表扫描。我自己的习惯是把第 3 节的查询脚本存成 SQL 片段排查时直接改SQL_ID就能跑。需要长期做 SQL 调优、经常跑自动化脚本的建议把 API Key 和接入文档过一遍接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的请求格式和模型列表。如果只是临时解读几条计划直接用模型对话页面 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 粘贴计划文本就行不用写代码。Key 的管理在控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite API Key 创建页 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 可以随时生成和吊销。最后提醒一句AI 解读执行计划只是辅助它标出的可疑点最终还是要你回到数据库里用DISPLAY_CURSOR验证。计划里的A-Rows和Buffers不会骗人结合业务语义判断索引是否该建、统计信息是否该收集才是慢 SQL 排查的落脚点。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。