尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ORACLE CURSOR 硬解析 Latch 争用?让 Codex 走 TaoToken 查 Parent/Child

ORACLE CURSOR 硬解析 Latch 争用?让 Codex 走 TaoToken 查 Parent/Child 数据库 CPU 飙到 99%AWR 又是 Shared Pool Latch。翻《基于ORACLE SQL优化》读书笔记Cursor 根因就两条找不到 Parent Cursor或找到 Parent 却匹配不上 Child Cursor于是硬解析。以前我要拿 V$SQLAREA、V$SQL 手工推演 Latch 持有过程现在让 Codex 走 TaoToken 通道查打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建 KeyBase URL 填 https://taotoken.net/api。这条排障路径改完之后查解析链的效率明显不一样。过去我自己对着 V$SQLAREA 数 version_count对着 V$SQL 逐行看 child_number判断 Shared Pool Latch 到底卡在哪一步基本靠翻书对号入座现在只需要把两张视图的结果原样贴回对话Codex 会告诉你该拆哪条 SQL、该调哪个参数。下面从最典型的报错现场说起。1. 硬解析现场CPU 飙高V$SQLAREA 和 V$SQL 对不上1.1 先确认是哪种硬解析某天中午数据库 CPU 打满抓 AWR 发现 Top 5 Wait Event 里是 library cache lock 和 shared pool latch活动会话大多停在同样的业务 SQL 上执行计划等不出来。这种局的直接原因往往不是 SQL 性能本身而是 Cursor 解析出了问题。Oracle 执行 SQL 前会先在 Shared Pool 里找共享的 Parent CursorParent Cursor 存的是 SQL 文本和指向 Child 的指针真正存解析树和执行计划的是 Child Cursor。两者合起来才是 Shared Cursor。硬解析的触发条件就两种第一种Shared Pool 里根本没有这个 SQL 文本对应的 Parent Cursor第二种Parent Cursor 在但按当前 session 条件匹配不到可用的 Child Cursor。一旦走了硬解析Oracle 就要重新做语法检查、权限检查、对象解析、优化器生成执行计划这一串动作既要扫描库缓存对象句柄链表又要到 Shared Pool 里分配内存Latch 就一把接一把地抢起来了。Shared Pool Latch 争用常见的副作用就是 CPU 占用率高因为大量 session 在自旋等待而不是真的在跑业务。1.2 两张视图这么看排障时我在 SQLPlus 里先跑两组查询。第一组看 V$SQLAREA确认这个 SQL 文本是否存在version_count 高不高第二组看 V$SQL确认所有 Child Cursor 的 plan_hash_value 和失效标记。注意这两步都在本地 SQLPlus 执行拿到结果后再交给 Codex 分析不要让 AI 工具直连生产库。-- 第一步确认 Parent Cursor 是否存在 SELECT sql_id, sql_text, version_count, loads, invalidations FROM v$sqlarea WHERE sql_text LIKE SELECT /* demo */ %; -- 第二步确认 Child Cursor 为什么对不上 SELECT sql_id, child_number, plan_hash_value, parses, loads, invalidations FROM v$sql WHERE sql_id 8X6X9X2X4Q3Y7 ORDER BY child_number;如果 V$SQLAREA 查不到 sql_text说明 Parent Cursor 已经被 age out每次执行都是从头解析如果查到了但 version_count 超过 10说明同一个 SQL 文本衍生出一堆 Child Cursor这时候要重点检查 session 级 NLS 参数、优化器模式、绑定变量长度是不是各不一样。把这两组的输出原样保存下一步贴给 Codex。2. 把 Codex 的模型通道切到 TaoToken2.1 拿 Key 这一步只需要两分钟以前做这种判断我得自己翻《基于ORACLE SQL优化》读书笔记里 Cursor 那一节把 Latch 持有链一条条背下来再对照当前现象猜原因。现在这一部分交给 Codex但我需要先给它配一个稳定的模型通道。官方通道的问题是高峰期额度经常不够用本机网络也不一定每次都连得顺。我的做法是把 Codex 的模型供应商切到 TaoToken它统一兼容常见的 API 格式注册、创建 Key、填 Base URL 三步就能接上。打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册并创建 API Key把生成的 Key 记成 YOUR_API_KEY。TaoToken 的定位是统一 API 接入和兼容通道不需要你准备多把 Key 来回试。注意这个落地页只负责注册、创建 Key、看模型广场和用量真正要填进 Codex 的地址是接口地址 https://taotoken.net/api两者不要混。2.2 config.toml 里把供应商指到 TaoTokenCodex 的配置文件在~/.codex/config.toml按下面的格式改model 在TaoToken模型广场复制的模型ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY再在 shell 里导出环境变量Key 从官网创建替换 YOUR_API_KEYexport TAOTOKEN_API_KEYYOUR_API_KEY提示base_url 填https://taotoken.net/api末尾不要加/v1更不要把官网落地页地址填进来。model 的值不要自己编也不能凭记忆猜一个日期后缀必须以 TaoToken 模型广场上实际写的模型 ID 为准。配置完在 Codex 对话框随便问一句它能正常返回就说明通道通着接下来可以开始干正事。3. 让 Codex 对照两张视图查 Parent/Child3.1 提示词给到这个粒度把第 1 节查到的 V$SQLAREA 和 V$SQL 结果整理成一段文字连同原始 SQL 一起贴给 Codex。提示词不要只写一句「帮我看看为什么 CPU 高」要给它完整的现场数据下面是一个 Oracle 硬解析现场。我在 SQL*Plus 执行了 V$SQLAREA 和 V$SQL 查询结果如下 - SQL_ID: 8X6X9X2X4Q3Y7 - V$SQLAREA: version_count15loads128invalidations3 - V$SQL: 有 15 个 child_numberchild 0-6 的 plan_hash_value 相同 child 7-14 的 plan_hash_value 各不相同 这是硬解析中的哪一种Parent Cursor 缺失还是 Parent 存在但 Child 失配 争用主要落在 Library Cache Latch 还是 Shared Pool Latch 下一步应该拆解哪几条 SQL或者先查哪些 session 参数Codex 走 TaoToken 通道返回的分析通常会按三步走先看 loads128 次加载说明 SQL 文本反复被重新解析再看 invalidations3说明有对象失效导致 Child Cursor 被重建最后按 plan_hash_value 分组判断是不是存在多个执行计划在打架。这个顺序和读书笔记里硬解析的判定逻辑一致但不用你再逐条翻。3.2 Child Cursor 太多时补一条定位失配项的 SQL如果 version_count 很大Child Cursor 各自差异不明显可以在本地再执行一条更细的查询把优化器模式、排序规则、绑定变量长度也带出来SELECT child_number, optimizer_mode, nls_sort, bind_variable_length, plan_hash_value FROM v$sql WHERE sql_id 8X6X9X2X4Q3Y7 ORDER BY child_number;把结果贴回对话Codex 会对照差异项判断如果 bind_variable_length 不一致说明应用里同一 SQL 用了不同长度的绑定变量如果 nls_sort 不一致说明 session 级 NLS 参数没有统一。这类问题在读书笔记里一句话就能带过真到现场却要试错半天现在等于让 Codex 替你做了这个比对。4. Latch 持有过程让 Codex 告诉你卡在哪一把锁4.1 读书笔记里的持有链化成排障清单《基于ORACLE SQL优化》读书笔记里有一段硬解析的 Latch 持有过程简化之后是这么回事先持有 Library Cache Latch沿库缓存对象句柄链表搜索找不到 Parent Cursor 就释放它如果找到了要继续为 Child Cursor 分配内存此时在持有 Library Cache Latch 的同时再持有 Shared Pool Latch分配完解析树和执行计划所需的内存后依次释放 Shared Pool Latch 和 Library Cache Latch。11gR1 之后部分库缓存相关 Latch 被 Mutex 替代但并发硬解析时 CPU 飙升的本质没变。软解析也会持有库缓存相关 Latch但持有时间短得多而且不会在持有 Shared Pool Latch 的情况下同时持有 Library Cache Latch。这个区别是判断问题的关键大量软解析顶多让 CPU 偏高一点点真正能把 CPU 打满的几乎都是硬解析期间两把锁同时握在手里的场景。4.2 把等待事件时序贴给 CodexLatch 持有过程看不见摸不着但可以从等待事件反推。把 AWR 里相关等待事件统计也贴给 Codex等待事件统计 shared pool latch: waits12345, time8.2s library cache latch: waits9800, time6.5s cursor: pin S wait on X: waits2310, time1.8sCodex 的解读思路是shared pool latch 高问题大概率在 Shared Pool 空闲内存分配优先查 shared_pool_size 是不是偏小、字面量 SQL 是不是太多library cache latch 高问题在库缓存链表太长优先查对象总数和 Child Cursor 数量如果大量 session 同时在解析同一个 SQL_ID那是同一个问题被并发放大了不是一个 session 一个原因。拿到这个结论再回头决定是改绑定变量还是加大 shared_pool_size方向就清楚多了。5. Session Cursor 和软软解析也一起看了5.1 Session Cursor 有自己的生命周期Shared Cursor 解决的是 SQL 文本和解析树的复用问题Session Cursor 则是和 session 一一对应的。每个 Session Cursor 都有 open、parse、bind、execute、fetch、close 这样的生命周期。Oracle 执行 SQL 前先要到 PGA 里找有没有缓存的 session cursor找到之后再把 Buffer Cache 里目标 SQL 涉及的数据块读到 PGA 里做后续处理比如排序、表连接。排障时容易忽略的是即使 Shared Pool 里有可用的 Child Cursor如果应用频繁地 open 和 close session cursor软解析产生的库缓存 Latch 持有时间也会被推高CPU 没那么容易降下来。5.2 软软解析要在统计项里识别软软解析比软解析更轻它省掉了重新 open 一个新 session cursor 所需的资源和时间同时也不用再做 close 老 session cursor 的额外动作直接复用当前已打开的游标执行即可。怎么判断系统有没有吃到这层红利把 V$SESSTAT 里的几个统计项贴给 Codexparse count (total): 85000 parse count (hard): 3000 execute count: 240000 session cursor cache hits: 70000Codex 会算一下硬解析率约 3.5%还算健康但总解析次数与执行次数的比值约 0.35偏高说明大量软解析没有走进 session cursor cache应用可能在循环里频繁 open/close。此时建议调大 session_cached_cursors或者改应用把游标拿出来复用。这一层过去要在笔记里反复比较三种解析的定义差别现在直接把统计项甩给 Codex 就行。6. 验证一次调用按报错反查配置6.1 用一次真实查询做联调配置完 TaoToken 并且把现场数据喂给 Codex 之后建议做一次完整联调在本地 SQL*Plus 执行第 3 节的查询语句把结果贴回 Codex 对话框要求它按「Parent/Child 判定 → Latch 争用定位 → 下一步拆解」的顺序输出结论。Codex 能按这个顺序正常回复就说明 Base URL、Key、模型 ID 三个配置项都是通的。如果回复质量不稳定先去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 确认一下模型广场上的模型版本再回 config.toml 检查 model 字段。6.2 报错就按三个位置查如果 Codex 报错不要急着改参数先看报错类型落在哪个位置。提示 unauthorized 或 authentication检查环境变量里 TAOTOKEN_API_KEY 是否真的换成了从 TaoToken 官网创建的 Key注意别把 YOUR_API_KEY 这个占位符原样留在配置里。提示 model not found检查 config.toml 的 model 字段。模型 ID 以 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 模型广场为准不能凭印象填也不要自己加后缀。提示 connection failed检查 base_url。填进 Codex 的地址必须是 https://taotoken.net/api末尾没有 /v1也不是官网落地页的地址。调通之后回到官网控制台看一眼刚才那几次对话有没有产生对应的调用记录。这样既验证了 Codex 确实走的是 TaoToken 通道也顺带确认了用量统计是正常的。下次再遇到 CPU 飙高我不用再抱着《基于ORACLE SQL优化》读书笔记逐条对先在 SQL*Plus 把 V$SQLAREA 和 V$SQL 的结果捞出来贴给 Codex让它对照 Latch 持有过程指出争用发生在哪一步、该拆解哪条 SQL。翻笔记的动作可以留给 Codex你只负责把现场数据带回来。
返回列表