ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

如何诊断 cursor pin s wait on x 系列一:用 AWR 与 ADDM 定位等待链

如何诊断 cursor pin s wait on x 系列一:用 AWR 与 ADDM 定位等待链 1. 先搞清楚 cursor pin s wait on x 到底卡在哪cursor: pin S wait on X这个等待事件第一次看到的人很容易被名字唬住。拆开看其实不复杂S 是共享SharedX 是排他Exclusive一个会话想以共享方式去 pin 住某个游标结果发现另一个会话正拿着这个游标的排他锁不放于是只能排队等。它本质是一个 mutex 层面的争用不是 IO也不是锁enqueue所以你在v$lock里翻半天往往什么都找不到。我见过太多人一上来就盯着这个等待事件本身调参数结果方向全错。要记住一句话cursor: pin S wait on X是症状不是根因。真正要回答的问题是——谁在持有 X 锁它为什么持有那么久。绝大多数情况下持有者正在做硬解析hard parse或者在做游标失效后的重新编译。硬解析本身要拿 library cache 上的 mutex解析越慢别人等得越久等待就像滚雪球一样堆起来。那为什么硬解析会频繁发生常见几类绑定变量没用好导致大量不可共享的游标high version count让一个 SQL 生成成百上千个子游标统计信息或 DDL 导致游标失效还有少数是版本 bug。这些原因在 AWR 和 ADDM 里其实都有痕迹只是需要你知道去哪一栏看。这篇是系列第一篇只讲首次排查路径怎么用 AWR 快照对比锁定异常时段怎么用 ADDM 报告拿到 Oracle 自己的判断再用 system state dump 把 holder 和 waiter 进程抓出来。全程给可复制的脚本和命令你照着敲就行。适合已经能登数据库、会看基本等待事件的 DBA 和运维同学。如果你手上正好有一套采集端点后面我也会说怎么把诊断数据统一收口避免每次排查都在几台机器之间来回拷 trace 文件。先明确排查顺序别乱第一步确认现象和时段第二步 AWR 对比找异常第三步 ADDM 看建议第四步 dump 抓现场第五步定位 blocker 和它的 SQL。顺序反了你会在 dump 文件里迷路。2. 排查前的准备AWR、ADDM 与统一采集端点动手之前先把工具链理清楚。AWR 是 Oracle 自带的历史性能仓库默认每小时一个快照保留期看你的配置。ADDM 是建立在 AWR 之上的自动诊断它会在每个快照间隔跑一次直接告诉你这段时间数据库认为最大的问题是啥。这两个是官方给的、不用额外装的东西排查cursor: pin S wait on X一定要先用它们而不是一上来就 dump。你需要确认几件事。第一当前用户有DBA角色或者至少能执行awrrpt.sql、addmrpt.sql。第二知道$ORACLE_HOME在哪因为脚本都在$ORACLE_HOME/rdbms/admin/下。第三确认 AWR 快照间隔和保留策略如果间隔太长比如 1 小时短时间的争用高峰可能被平均掉这时候要结合v$active_session_history做细粒度看。-- 查看当前 AWR 配置 SELECT snap_interval, retention FROM dba_hist_wr_control; -- 查看最近的快照确定异常时段对应的 snap_id SELECT snap_id, begin_interval_time, end_interval_time FROM dba_hist_snapshot ORDER BY snap_id DESC FETCH FIRST 20 ROWS ONLY;关于采集端点这里说一个实际痛点。排查这类问题经常要跨多套库、多个时间点收集 AWR 文本、ADDM 文本、trace 文件散落在不同机器上事后复盘很难对齐。我的做法是把这些诊断产物的采集和归档统一走一个通道用 TaoToken 的 API 端点做集中管理把每次排查的 AWR/ADDM 报告、dump 摘要按事件归档后面写复盘或者做基线对比时直接调。它的接入地址是https://taotoken.net/api控制台在https://taotoken.net/consoleAPI Key 在https://taotoken.net/api-keys生成。注意这里只是把诊断数据的采集与归档这件事收口数据库本身的 AWR 还是 Oracle 原生的两者不冲突。如果你只是想先把这次排查做完可以跳过归档直接用原生脚本。但如果你是要做长期性能治理建议一开始就把端点配好省得后面补。配置方式在下一节给。3. 可复制配置AWR/ADDM 脚本与采集端点设置这一节全是能直接抄的东西。先做 AWR 报告交互式脚本会问你 snap 范围正常时段和异常时段各出一份用来做基线对比。-- 交互式生成 AWR 报告文本格式 SQL $ORACLE_HOME/rdbms/admin/awrrpt.sql -- 提示选择 report_type: text -- 提示输入天数: 1 -- 提示输入 begin_snap 和 end_snap: 选异常时段如果你不想交互可以用awrrpti.sql指定实例或者直接查dba_hist视图自己算。下面这段是我常用的直接定位异常时段里cursor: pin S wait on X的等待占比和 top SQL-- 异常时段内该等待事件的总体情况 SELECT event, total_waits, time_waited_micro/1000000 AS wait_sec, average_wait_micro/1000 AS avg_ms FROM dba_hist_system_event WHERE event cursor: pin S wait on X AND snap_id BETWEEN begin_snap AND end_snap ORDER BY snap_id; -- 该时段 top SQL按 elapsed time SELECT sql_id, executions, elapsed_time/1000000 AS elapsed_sec, parse_calls, version_count FROM dba_hist_sqlstat WHERE snap_id BETWEEN begin_snap AND end_snap ORDER BY elapsed_time DESC FETCH FIRST 20 ROWS ONLY;ADDM 报告同样用官方脚本它会直接给出硬解析过多library cache 争用这类结论SQL $ORACLE_HOME/rdbms/admin/addmrpt.sql -- 选择异常时段的 begin_snap / end_snap接下来是采集端点的配置。TaoToken 的接入用标准 API Key 方式把诊断产物的归档请求指向https://taotoken.net/api。下面是一个 JSON 配置片段路径按你实际的归档脚本目录放比如/opt/diag/collector/config.json{ endpoint: https://taotoken.net/api, api_key: sk-你的key, model_id: diagnostic-archive, base_url: https://taotoken.net/api, archive: { awr_dir: /opt/diag/awr, addm_dir: /opt/diag/addm, trace_dir: /opt/diag/trace, tag: cursor_pin_s_wait_on_x } }三件套要写全Base URL 是https://taotoken.net/apiKey 从https://taotoken.net/api-keys拿Model ID 按你归档任务的定义填。如果你用的是 Cline 这类带 MCP 的客户端配置里同样要保证这三项齐全缺一个就会报local proxy failed或者 401。Codex 用户如果走auth.json也要把 base_url 和 key 对齐别只填一半。配好之后每次排查产出的 AWR/ADDM 文本、dump 摘要都往这个端点推tag 统一用cursor_pin_s_wait_on_x后面按 tag 检索就能把同一类问题的历史现场全捞出来。这一步不是必须但做过一次你就知道多省事。4. 验证请求与成功结果dump 抓现场并定位 blockerAWR 和 ADDM 给的是面system state dump 给的是点。当 AWR 没抓到异常 SQL或者你需要精确知道谁持有 X 锁时就得 dump。先看非 RAC 环境-- 非 RAC连续三次 dump间隔 90 秒观察变化 SQL oradebug setmypid SQL oradebug unlimit SQL oradebug dump systemstate 266 -- 等待 90 秒 SQL oradebug dump systemstate 266 -- 等待 90 秒 SQL oradebug dump systemstate 266 SQL oradebug tracefile_name SQL quitRAC 环境用 hanganalyze 加 systemstate注意-g all是对所有实例$ sqlplus / as sysdba SQL oradebug setmypid SQL oradebug unlimit SQL oradebug setinst all SQL oradebug -g all hanganalyze 4 SQL oradebug -g all dump systemstate 267 SQL oradebug tracefile_name SQL quitdump 出来之后怎么快速定位 blocker其实不用每次都翻巨大的 trace。v$session里的P2RAW列直接给出了阻塞会话。10g 和 11g 的解析方式不同注意位数-- 10g 32bit SELECT p2raw, TO_NUMBER(SUBSTR(TO_CHAR(RAWTOHEX(p2raw)),1,4),XXXX) AS sid FROM v$session WHERE event cursor: pin S wait on X; -- 10g 64bit SELECT p2raw, TO_NUMBER(SUBSTR(TO_CHAR(RAWTOHEX(p2raw)),1,8),XXXXXXXX) AS sid FROM v$session WHERE event cursor: pin S wait on X;拿到 sid 后确认阻塞会话SELECT sid, serial#, sql_id, blocking_session, blocking_session_status, event FROM v$session WHERE sid blocker_sid;11g 更省事BLOCKING_SESSION直接可用SELECT sid, serial#, sql_id, blocking_session, blocking_session_status, event FROM v$session WHERE event cursor: pin S wait on X;成功的结果长这样BLOCKING_SESSION_STATUS显示VALIDBLOCKING_SESSION有具体 sid顺着这个 sid 查它的sql_id就能看到那条正在硬解析的 SQL。再查 waiter 侧SELECT s.sid, t.sql_text FROM v$session s, v$sql t WHERE s.event LIKE %cursor: pin S wait on X% AND t.sql_id s.sql_id;如果已经确定了 blocker 进程还想看它到底卡在解析的哪一步用 errorstackSQL oradebug setospid blocker_spid SQL oradebug dump errorstack 3 -- 等待 1 分钟 SQL oradebug dump errorstack 3 -- 等待 1 分钟 SQL oradebug dump errorstack 3 SQL exit三次 errorstack 是为了看调用栈有没有推进。如果三次栈顶几乎一样说明它真的卡住了不是慢而是死等。到这一步holder、waiter、SQL、执行计划基本都齐了可以进入根因分析。5. 本篇常见报错排查清单排查过程中最容易撞的几个坑我按真实报错列一下。第一个ORA-00054: resource busy或者 dump 时提示权限不足。这通常是oradebug需要sysdba权限普通 DBA 账号不行。确认你用sqlplus / as sysdba登录或者有SYSDBA角色。另外oradebug setmypid必须在当前会话先执行顺序错了后面全废。第二个local proxy failed。这个多半出现在你用带 MCP 的客户端去连采集端点时配置里 Base URL 或 Key 没写全。检查三件套Base URL 是不是https://taotoken.net/apiKey 是不是从https://taotoken.net/api-keys拿的最新值Model ID 有没有填。Cline 的 MCP 配置里这三项缺一不可Codex 的auth.json同理只填 key 不填 base_url 一样会失败。第三个401 未授权。Key 过期、复制时带了空格、或者用了别的环境的 key。重新生成一个注意别把换行符带进去。如果是在settings.json里配的检查 JSON 有没有语法错误一个多余的逗号就会让整个配置失效。第四个reading choices相关报错。这通常发生在解析返回结果时端点返回的不是预期结构可能是请求体格式不对或者 model_id 写错了。对照文档https://taotoken.net/doc检查请求字段。第五个dump 文件巨大导致磁盘告警。system state dump 在进程多的时候能到几个 G这就是为什么前面说不是特别建议无脑 dump。优先用P2RAW定位 blocker实在需要 dump 再 dump并且 dump 完及时清理。RAC 环境用-g all更要小心四个节点一起 dump 磁盘压力翻倍。第六个AWR 里根本看不到cursor: pin S wait on X。可能是快照间隔太长把峰值平均掉了或者等待时间太短没进 top。这时候去查v$active_session_history按秒级采样看SELECT sample_time, session_id, sql_id, event FROM v$active_session_history WHERE event cursor: pin S wait on X AND sample_time SYSDATE - 1/24 ORDER BY sample_time;第七个BLOCKING_SESSION_STATUS显示UNKNOWN或NO HOLDER。说明 holder 在采样瞬间已经释放了或者你查的时机不对。这种情况要连续多次查询或者直接上 dump 抓瞬时状态。别指望一次查询就抓到争用是动态的。把这几条对照着过一遍大部分首次排查的卡点都能解开。真正难的不是命令是判断这次到底是硬解析、version count 还是 bug那需要结合 AWR 的 parse 相关指标和v$sql的version_count一起看这个留到系列后面讲。6. 把诊断数据收口下次排查快一半第一次排查cursor: pin S wait on X最耗时的往往不是分析而是找数据AWR 在哪台机器、trace 文件叫什么、上次类似问题的现场还在不在。我现在的习惯是每次排查完把 AWR 文本、ADDM 文本、dump 摘要、blocker 的 SQL 和执行计划按统一 tag 归档到采集端点。下次再遇到先按 tag 捞历史基线直接就有了。归档走https://taotoken.net/apiKey 在https://taotoken.net/api-keys控制台https://taotoken.net/console能看归档任务状态。如果你要长期做性能治理尤其是多套库、多实例的场景建议把 Coding Plan 也用上把采集脚本、分析脚本、报告模板统一管理省得每次手敲。模型对话入口在https://taotoken.net/models调试归档请求格式的时候可以直接在那试。最后给一个实用技巧给每次排查建一个目录命名用日期_事件_tag比如20240923_cursorpin_tagAWR、ADDM、dump 摘要、结论各一个文件。归档时整个目录推上去。三个月后你回头看这套结构能让你在十分钟内重建任何一次现场。排查这件事快不快取决于你上次有没有留好底。
返回列表