
Oracle SQL 执行计划最劝退的是 DISPLAY_CURSOR 拉出来后 cost 四千多、cardinality 写 21K实际 A-Rows 却只有几十行。TaoToken 可以帮上忙先到 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_content 拿 API Key再把 Codex 的模型通道指向 https://taotoken.net/api之后把执行计划原文贴给 Codex让它按 DISPLAY_CURSOR 的格式逐行拆解。这条链路里TaoToken 只做 Codex 的兼容接入通道真正解释 cost、cardinality、Rows、Time 并帮你定位瓶颈的仍然是 Codex。下面就从原文的目录顺序走一遍执行计划作用、示例演示、两种取计划入口、指标详解每一步都落到可操作的位置。1. 执行计划是优化器的“行车记录仪”不是一张考核表1.1 执行计划到底记了什么Oracle 拿到一条 SQL 后并不会直接按 SQL 字面顺序去跑。优化器会根据表统计信息、索引、系统参数生成多条候选执行路径再从中选一条它认为成本最低的路径。执行计划就是这条被选中的路径的完整记录哪个表先访问、哪张表作为驱动表、两个表之间用什么连接方式、过滤条件在哪个阶段生效、有没有走全表扫描都会在计划里体现。很多人读不懂执行计划不是因为缺少 Oracle 基础而是把 cost、cardinality、Rows、Time 这四个数字当成了“性能评分”。实际上它们是优化器的估算账本不是最终成绩单。cost 表示优化器评估的成本分单位不是秒cardinality 表示预计返回的行数不是真实行数Rows 在不同输出格式下可能是估算行数也可能是真实行数要看来源Time 是估算耗时不能直接当成实际响应时间。理解这层关系后再看计划你会发现计划里每一行都在回答同一个问题优化器为什么选了这条路径以及它预计每一步要处理多少行。1.2 一个可以反复用的示例 SQL 与执行计划原文在示例演示部分用了一条带聚合的 SQL。这里用相似的形态构造一个具体例子按城市统计已付款订单的金额。为了让计划有讨论价值这条 SQL 假设订单表数据量比较大且当前没有合适的索引。SELECT c.cust_city, SUM(o.order_amount) AS total_amount FROM orders o JOIN customers c ON c.cust_id o.cust_id WHERE o.order_status PAID AND o.order_time DATE 2024-01-01 GROUP BY c.cust_city;通过 DBMS_XPLAN 拿到的执行计划大致长这样--------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 52 | 2108 | 4123 (1) | 00:00:01 | | 1 | HASH GROUP BY | | 52 | 2108 | 4123 (1) | 00:00:01 | | 2 | HASH JOIN | | 21K | 873K | 4119 (1) | 00:00:01 | | 3 | TABLE ACCESS FULL | ORDERS | 980K| 17M | 4101 (1) | 00:00:01 | | 4 | TABLE ACCESS FULL | CUSTOMERS | 52 | 936 | 4 (0) | 00:00:01 | ---------------------------------------------------------------------------先看缩进与执行顺序。Id 3 和 Id 4 在最内层通常先执行分别全表扫描 ORDERS 和 CUSTOMERS。Id 2 把两个结果集做 HASH JOINId 1 对连接结果做分组聚合Id 0 把最终结果返回给客户端。注意 Id 3 的 Cost 是 4101占整个计划 4123 的绝大部分所以第一瓶颈大概率在 ORDERS 的全表扫描上。再看 Rows 与 cardinality 的矛盾点。Id 2 的 Rows 只有 21K而 Id 3 全表扫描 ORDERS 预估返回 980K 行Id 4 返回 52 行。也就是说优化器相信通过 order_status 和 order_time 的条件过滤后980K 行会被大幅减少到 21K。这个估算是否准确就需要拿到真实执行统计后再去对比 A-Rows。如果实际过滤后仍然有 90 万行那说明优化器严重低估了基数执行计划可能选了错误路径。2. 两种取执行计划的入口DISPLAY_CURSOR 和 DISPLAY_AWR2.1 先用 SQL 文本定位 SQL_ID无论使用 DISPLAY_CURSOR 还是 DISPLAY_AWR第一步都是拿到 SQL_ID。SQL_ID 是 Oracle 根据 SQL 文本生成的哈希标识也是执行计划查询的定位键。如果 SQL 仍然在库缓存里可以通过 V$SQL 查询SELECT sql_id, sql_text FROM v$sql WHERE sql_text LIKE %FROM orders o% AND sql_text NOT LIKE %FROM v$sql%;如果 SQL 已经不在库缓存中但 AWR 快照还保留着历史信息可以换到 DBA_HIST_SQLTEXT 查询SELECT sql_id, sql_text FROM dba_hist_sqltext WHERE sql_text LIKE %FROM orders o%;拿到 SQL_ID 后把它替换到下面的查询语句中就能得到对应的执行计划。注意 SQL_ID 是大小写敏感的复制时不要手打建议直接从 V$SQL 返回结果里选中复制。2.2 DISPLAY_CURSOR看“刚才那条 SQL”真实走过的路径EXPLAIN PLAN 最大的问题是不执行 SQL它是纯推演偶尔会和真实执行路径不一致。DISPLAY_CURSOR 读的是库缓存里的游标计划也就是 SQL 实际使用过的那份执行计划因此排障时更有参考价值。使用方式如下SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR( sql_id YOUR_SQL_ID, format ALLSTATS LAST));format 参数写成 ALLSTATS LAST目的是带上真实执行统计。只要会话在执行前开启了 statistics_levelall或者在 SQL 中加了 gather_plan_statistics 提示计划里就会多出 A-Rows、A-Time、Starts 三列。A-Rows 是每个步骤实际处理的行数A-Time 是实际耗时Starts 是该步骤实际执行次数。没有这三列你就只能看优化器的估算值很难判断 Rows 到底偏差了多少。如果只是想快速看一眼计划结构不关心真实统计可以把 format 改成 TYPICAL 或直接省略 format 参数。但要回答“这条 SQL 为什么慢”这种问题建议始终优先看 ALLSTATS LAST。2.3 DISPLAY_AWR翻历史账找偶发慢的根因AWR 快照会定期收集数据库的运行统计信息包括 SQL 执行计划和执行次数。当一条慢 SQL 已经从库缓存里被挤出去或者你想对比它在不同时间段的表现DISPLAY_AWR 可以从历史快照中把计划找出来SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR( sql_id YOUR_SQL_ID, db_id NULL, format TYPICAL));DISPLAY_AWR 与 DISPLAY_CURSOR 的适用场景差异可以这样理解维度DISPLAY_CURSORDISPLAY_AWR数据来源库缓存 cursor cacheAWR 历史快照适合场景当前或最近执行的 SQLSQL 已过缓存期需要历史回溯真实执行统计配合 ALLSTATS 可看到 A-Rows / A-Time通常只有估算值典型用途定位当前慢 SQL 的具体瓶颈对比计划变化排查偶发性能反转原文在 DISPLAY_AWR 类型上花了不少篇幅核心就一句话AWR 是历史账本适合回答“这条 SQL 是最近变慢还是一直这么慢”。3. Codex 读执行计划之前先让它走通 TaoToken 通道3.1 先从 TaoToken 拿一把 API KeyCodex 需要一个兼容的模型接口。打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_content 注册登录后在控制台创建 API Key复制下来作为 YOUR_API_KEY。这把 Key 同时用于 Codex 的鉴权和后续用量统计不要提交到 Git 仓库也不要写进 SQL 脚本里。TaoToken 在这条链路里扮演的是兼容接入通道Codex 只需要认 Base URL 和 Key就能把请求发送到对应模型。它不会替你做执行计划分析更不会替你连 Oracle 执行 SQL。分析动作仍然发生在 Codex 侧你负责提供完整的执行计划文本Codex 负责解释。3.2 修改 ~/.codex/config.toml把模型通道指向 TaoTokenCodex 的配置目录是 ~/.codex它不读 ANTHROPIC_BASE_URL 这类环境变量而是使用自己的 model_provider 配置。编辑 ~/.codex/config.toml加入以下内容model_provider taotoken model YOUR_MODEL_ID [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY这里有几个容易填错的地方需要特别说明。Base URL 必须写成 https://taotoken.net/api末尾不要加 /v1也不要把官网首页 https://taotoken.net/ 当成接口地址填进去。env_key 表示 Codex 会从环境变量 TAOTOKEN_API_KEY 读取密钥因此还需要在 shell 里导出export TAOTOKEN_API_KEYYOUR_API_KEY如果你习惯把密钥放在配置文件里也可以把环境变量对应的内容写到 ~/.codex/auth.json{ TAOTOKEN_API_KEY: YOUR_API_KEY }model 字段不能凭记忆写。先打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_content 的模型广场复制当前可用的模型 ID再替换掉 YOUR_MODEL_ID。不同时间段模型列表会变不要使用网上旧教程里写死的模型名。3.3 用一条最小指令验证 Codex 通道已通配置保存并导出环境变量后先用一个简单任务验证连通性不要直接扔执行计划。比如运行codex exec 请用 50 字解释 Oracle 执行计划里的 cardinality 是什么。如果 Codex 正常返回内容说明 Base URL、Key、模型 ID 三个配置都正确。如果这一步就报错先回到配置检查不要急着分析执行计划。验证通过后再把真正的 DISPLAY_CURSOR 输出丢给 Codex。4. 让 Codex 按 DISPLAY_CURSOR 逐项拆解示例计划4.1 贴给 Codex 的执行计划必须带完整谓词信息很多人把执行计划复制给 AI 时只截表格部分把 Predicate Information 段落剪掉这是最可惜的操作。DBMS_XPLAN 输出在计划表格下方通常会有一段 Predicate Information包含 access 和 filter 两类条件。access 表示访问路径时的关联条件比如两个表的连接字段filter 表示每一步返回结果前要过滤的条件。没有这一段Codex 就无法判断索引是做等值匹配还是仅仅被用作了 filter 的辅助。把第 1.2 节完整执行计划连同 Predicate Information 一起复制给 Codex并附上一段明确的任务描述请按 DISPLAY_CURSOR 的格式逐行拆解这张 Oracle 执行计划 1. 按操作树从内到外说明执行顺序 2. 指出 Cost、Rows 与 A-Rows 之间偏差最大的步骤 3. 说明 HASH JOIN 的驱动表是哪一边 4. 标注哪一步可以通过索引或统计信息更新来优化。Codex 会沿着这个框架回答。你贴给它的执行计划越完整它的判断就越有据可循。它只能基于你提供的文本分析不会自己连接 Oracle 去执行 SQL后续需要验证它给出的 SQL 建议由你在本地 SQL*Plus 或其他客户端执行再把结果贴回对话继续追问。4.2 指标详解cost、cardinality、Rows、Time 谁先看原文最后一部分的指标详解正好可以在这里对照执行计划实际使用。cost 是优化器内部的成本评分不是时间。它综合了 I/O、CPU 和内存开销的估算但不同版本的 Oracle 对 cost 的算法不完全一致所以跨库比较 cost 意义不大应该在同一份计划里看 cost 分布。哪一行占整棵计划的成本比例最高瓶颈通常就在哪。cardinality 是优化器估算的行数也就是计划输出里的 Rows 列。它代表“优化器认为这一步会返回多少行”不是真实行数。真实行数要看 DISPLAY_CURSOR 配合 ALLSTATS LAST 输出中的 A-Rows。cardinality 与 A-Rows 差一个数量级很常见差两个数量级以上就值得警惕通常意味着统计信息过期、直方图缺失或者绑定变量窥视问题。Time 是优化器预测的耗时和真实墙钟时间不是一回事。执行计划里的 Time 只反映优化器对成本的换算实际慢不慢要以 A-Time 或应用侧等待事件为准。因此正确读法是先看 cardinality 是否离谱再看 cost 分布最后用 A-Rows 验证。如果 cardinality 本身估错cost 再高也只是建立在错误假设上的高。4.3 让 Codex 输出下一步检查清单而不是停在解释解析完执行计划后下一步动作往往比解释更重要。可以追加一条指令把 Codex 的结论变成可执行的排障清单基于刚才的执行计划请输出一个不超过 5 条的检查清单。 每条包含现象、可能原因、在本地用哪条 SQL 验证。举例来说如果 Codex 认为 ORDERS 全表扫描成本异常它可能会建议你检查 DBA_TAB_STATISTICS 中 orders 表的 last_analyzed、num_rows以及 order_status 字段的直方图信息。你在本地执行查询后把结果贴回对话Codex 可以根据新的统计信息继续收敛问题。注意这里的 SQL 都是生成给你、由你本地执行的Codex 不直接操作数据库。5. DISPLAY_AWR 场景让 Codex 帮你对比历史计划5.1 AWR 计划里能挖到哪些信息DISPLAY_AWR 返回的执行计划不会像 ALLSTATS LAST 那样带真实 A-Rows因为 AWR 只保留汇总统计和计划文本没有每一行的实际执行行数。它能提供的是快照时间范围、执行次数、平均 elapsed time等上下文。这些信息组合起来可以判断 SQL 是偶发慢还是持续慢以及同一条 SQL 是否在不同时间段出现了不同计划。如果一条 SQL 平时 200 毫秒某个业务高峰突然跑到 20 秒优先怀疑执行计划发生了变更。这时可以把两个快照周期内的 DISPLAY_AWR 计划都拉出来放到同一个对话里对比。5.2 给 Codex 一份“历史对比”专用提示词把同一 SQL_ID 在两个 AWR 快照里的计划文本一起贴给 Codex然后这样提问这是同一 SQL_ID 在两个 AWR 快照周期里的执行计划。 请对比两次计划的 Cost、Rows、连接方式和谓词顺序 指出哪些差异可能导致性能发生反转。Codex 会注意到原本走 NESTED LOOPS 的计划变成了 HASH JOIN或者原本存在 index range scan 的地方退化成了 TABLE ACCESS FULL。你再用这些差异回到原文去看 DISPLAY_AWR 类型对应的字段含义整个排障链条就闭合了。AWR 计划拿不到 A-Rows所以对比重点放在执行路径和 Cost 分布上不要试图从历史计划里读取真实行数。6. 接入与排障哪些问题来自配置哪些问题来自执行计划6.1 Codex 接入 TaoToken 常见的三类报错Codex 配置完成后可能遇到的报错并不多。第一类是 401表示 Key 无效或环境变量没有生效。检查 shell 里是否执行过 export TAOTOKEN_API_KEYYOUR_API_KEY以及 config.toml 中的 env_key 是否和变量名完全一致。第二类是 404说明 Base URL 写错了。配置里要填 https://taotoken.net/api不是 https://taotoken.net/api/v1更不是 https://taotoken.net/ 官网首页。第三类是模型不存在的提示通常是 model 字段填了一个模型广场当前不存在的 ID去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_content 模型广场重新复制即可。这三类报错都有一个共同点问题出在 Codex 的通道配置而不是执行计划本身。先通过 3.3 节的最小指令验证通道确认识别通道通了再讨论 SQL 优化避免把两个层面的问题混在一起排查。6.2 执行计划解读本身最容易误判的三个地方第一cost 高不代表 SQL 慢。执行计划只是优化器的估算产物估算一旦出错就会出现 cost 很高但实际很快或者 cost 不高但慢得离谱的情况。判断慢不慢永远要把真实执行统计 A-Time 拉出来看。第二没有 A-Rows 时不要把 Rows 当真实行数。默认 TYPICAL 格式只显示优化器估算值要拿到实际行数必须用 DISPLAY_CURSOR 的 ALLSTATS LAST 格式并且确保执行前启用了 gather_plan_statistics 或 statistics_levelall。第三不要丢掉 Predicate Information。很多人在贴执行计划时会忽略表格下方的访问与过滤条件只留 Id、Operation、Rows、Cost 那些列。Codex 拿到完整文本才能准确判断索引是否被有效利用。到这里标题里的问题已经有了明确答案行。Codex 并不关心底层模型通道由哪个服务商提供它只知道配置里有一个兼容 Base URL 和一把 Key。执行计划还是那份执行计划分析质量取决于你贴给它的上下文是否完整。想继续验证同一把 Key 的对话效果可以在 TaoToken 模型对话 发一条测试消息如果日常 SQL 排障的调用量不小建议到 Coding Plan 看套餐是否匹配。Key 的创建、复制和用量核对都在 控制台 API Keys以后想接 Claude CodeBase URL 仍然填 https://taotoken.net/api环境变量格式参考 TaoToken 接入文档。