ITPub博客

首页 > 数据库 > Oracle > oracle如何查parse error对应的SQL

oracle如何查parse error对应的SQL

原创 Oracle 作者:dingjun123 时间:2026-05-16 22:47:02 0 删除 编辑

核心原则:为什么查询 Parse Error 如此特殊?

关键原因 :Parse Error(解析错误)发生在 SQL 语句的 语法检查/语义分析 阶段。在这个阶段,SQL 语句 根本没有成功进入共享池(Shared Pool) ,因此像 V$SQL 、 DBA_HIST_SQLTEXT 这样的常规视图 无法捕获到它们 。

Oracle 版本与核心方法速览

方法 Oracle 12.2 之前 Oracle 12.2 及之后 推荐度
方法A:手动开启 10035 事件 唯一官方手段 依然有效 ★★★★★(通用)
方法B:利用内置阈值告警 不支持 推荐 ( _kks_parse_error_warning ) ★★★★★(12.2+)
方法C:利用 Alert Log 中的地址反查 需配合 10035 需配合方法A或B ★★★★(定位源头)

方法详解与实战步骤

方法A:开启 10035 事件(最通用)

10035 事件会强制数据库将所有解析错误的详细信息实时写入 Alert Log(告警日志)。

操作流程:

  1. 开启捕获 (根据问题范围选择):

    sql
    -- 会话级:只抓当前会话的错误,最安全ALTER SESSION SET events '10035 trace name context forever, level 1';-- 系统级:抓全库所有会话的错误,谨慎使用(排障期间短时开启)-- ALTER SYSTEM SET events '10035 trace name context forever, level 1';
  2. 复现问题 :让应用程序或业务系统正常运行,触发解析错误。

  3. 查看 Alert Log :

    bash
    # 使用 tail 实时查看或 grep 过滤历史tail -f $ORACLE_BASE/diag/rdbms/<SID>/<SID>/trace/alert_<SID>.log | grep -A2 "PARSE ERROR"# 或一次性提取所有解析错误grep -A1 "PARSE ERROR" alert_<SID>.log > /tmp/parse_errors.log
  4. 关闭捕获 :

    sql
    ALTER SESSION SET events '10035 trace name context off';-- 或 ALTER SYSTEM SET events '10035 trace name context off';

输出示例:

text
PARSE ERROR: ospid=4577, error=923 for statement:
select count(*) frm dual
  • ospid :操作系统进程ID。

  • error :Oracle 错误码(如 942:表不存在;923:语法错误;904:列名无效)。

  • statement: :后面就是导致解析失败的 完整 SQL 文本 。

优点 :直接、通用,能立即看到错误SQL。
缺点 :开启期间会记录 所有 解析错误,可能使 Alert Log 急剧增长。


方法B:利用 12.2+ 内置阈值(最省心)

从 Oracle 12.2 开始,引入了一个隐含参数 _kks_parse_error_warning (默认值 100)。当 同一条 SQL 语句 在短时间内解析失败次数达到此阈值时,数据库会自动在 Alert Log 中打印警告信息, 无需手动开启 10035 事件 。

操作流程:

  1. 查看 Alert Log ,寻找类似条目:

    text
    ORCL(3):WARNING: too many parse errors, count=100 SQL hash=0x19a22496
    ORCL(3):PARSE ERROR: ospid=4577, error=923 for statement:
    ORCL(3):select count(*) frm dual

    它会直接输出 SQL 语句。

  2. (可选)调整灵敏度 :如果想更早捕获,可以降低阈值(需要重启):

    sql
    ALTER SYSTEM SET "_kks_parse_error_warning"=10 SCOPE=spfile;

    注意 :这是隐含参数,修改需谨慎。

优点 :自动化,无性能开销,不污染日志。
缺点 :仅限 12.2+;需达到阈值才记录,可能错过偶发错误。


方法C:利用 Alert Log 中的地址反查(定位问题代码)

当你在 Alert Log 中看到 PARSE ERROR 时,通常会伴随 hd 和 phd 地址信息。这两个地址是 内存中游标对象的指针 ,可以用来反向查询到 是谁在执行这条错误SQL (尤其当 SQL 是动态拼接在匿名块或过程中时)。

核心概念:

  • phd : 父游标地址 ( KGLHDPAR ),对应 V$SQLAREA.ADDRESS 。

  • hd : 子游标地址 ( KGLHDADR ),对应 V$SQL.CHILD_ADDRESS 。

操作流程:

  1. 从 Alert Log 中提取地址 :

    text
    Additional information: hd=0x7673c258 phd=0x765151a8 ...
  2. 转换地址格式 :去掉 0x ,左侧补0至16位(64位系统)。

    • hd=0x7673c258 -> '000000007673C258'

    • phd=0x765151a8 -> '00000000765151A8'

  3. 执行反查 :

    sql
    -- 方案1:查询父游标(最常用,通常能定位到调用它的PL/SQL块)SELECT sql_id, sql_text, users_executing, loads, parse_callsFROM v$sqlareaWHERE address = HEXTORAW('00000000765151A8');  -- phd-- 方案2:精确查询子游标(如果还在内存中)SELECT child_address, plan_hash_value, executions, parse_calls, sql_textFROM v$sqlWHERE child_address = HEXTORAW('000000007673C258');  -- hd-- 方案3:终极兜底,查询内核对象表 x$kglob (需SYSDBA权限)-- 当V$SQL中记录已被刷出时使用SELECT kglnaobj AS sql_text, kglobt03 AS execs, kglobt04 AS parsesFROM x$kglobWHERE kglhdadr = HEPTORAW('000000007673C258')   -- hd
      AND kglhdpar = HEXTORAW('00000000765151A8');  -- phd

示例结果 :通过查询父游标,你可能会发现错误的 SQL 被包裹在一个循环执行的匿名 PL/SQL 块中,从而找到问题根源。


总结与最佳实践建议

  1. 诊断流程 :

    • 第一步(所有版本) :检查 Alert Log,搜索 PARSE ERROR 或 too many parse errors 。

    • 第二步(12.2+) :如果日志中已有自动记录,直接分析 SQL 和错误码。

    • 第三步(若无记录) :在业务低峰期, 短时间开启会话级 10035 事件 ,复现问题后立即关闭。

    • 第四步(定位根源) :利用 Alert Log 中打印的 hd / phd 地址,反查 V$SQLAREA ,找到调用该错误 SQL 的上级代码(PL/SQL块、应用模块等)。

  2. 关键要点 :

    • 10046 事件不行 :10046 是 SQL 跟踪,用于已成功解析的语句。解析错误发生在更早阶段,必须用 10035 。

    • 及时关闭 :使用 10035 事件后务必关闭,避免日志爆炸。

    • 结合 AWR/ADDM :如你所说, failed parse 指标高、 latch: shared pool 等待、ADDM 建议,这些都是需要调查解析问题的 信号 ,但具体 SQL 仍需通过上述方法捕获。

    • 错误码解读 :用 oerr ora <错误码> 命令快速了解错误原因(如 oerr ora 942 )。

通过这套组合拳,你就能精准地抓出那些“看不见”的解析错误 SQL,并定位到问题源头,从而进行修复或优化。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/7655508/viewspace-3146062/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2008-05-07

  • 博文量
    45
  • 访问量
    90557