You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle VPD无侵入追踪INSERT操作调用栈的方案咨询

Oracle 19c追踪INSERT操作完整调用栈方案

(a) 优化现有VPD策略函数获取完整调用栈

之前的策略函数仅能拿到匿名调用信息,是因为没用到适配Oracle 19c的调用栈获取工具。12.1及以上版本支持的UTL_CALL_STACK包可以直接抓取完整嵌套调用链,包含所有层级的存储过程、函数和匿名块。

修改策略函数ING_PIM_DOC_CAT_PLY_FN的核心逻辑,替换原调用栈获取代码,示例如下:

DECLARE
  l_depth PLS_INTEGER;
  l_owner VARCHAR2(128);
  l_name VARCHAR2(128);
  l_line PLS_INTEGER;
  l_call_stack CLOB := EMPTY_CLOB();
BEGIN
  -- 获取调用栈层级深度
  l_depth := UTL_CALL_STACK.Dynamic_Depth;
  -- 遍历每一层调用栈,收集所有者、程序名、行号信息
  FOR i IN 1..l_depth LOOP
    l_owner := UTL_CALL_STACK.Owner(i);
    l_name := UTL_CALL_STACK.Concat_Subprogram(i);
    l_line := UTL_CALL_STACK.Line(i);
    l_call_stack := l_call_stack || CHR(10) || '层级 ' || i || ': ' || l_owner || '.' || l_name || ' (行号 ' || l_line || ')';
  END LOOP;
  -- 将调用栈写入临时表t1,同时记录操作时间和用户
  INSERT INTO t1 (call_stack, event_time, username)
  VALUES (l_call_stack, SYSTIMESTAMP, USER);
  -- VPD策略需返回过滤条件,这里返回1=1不影响INSERT执行
  RETURN '1=1';
END;

注意事项:

  • 给策略函数的执行用户授予UTL_CALL_STACK包的执行权限:GRANT EXECUTE ON SYS.UTL_CALL_STACK TO <your_user>;
  • VPD策略在INSERT执行前触发,此时抓取的调用栈能完整反映触发INSERT的嵌套调用链路,不会遗漏层级。

(b) 无需修改核心代码的其他追踪方式

方案1:AFTER INSERT触发器+UTL_CALL_STACK

直接给目标表创建后置INSERT触发器,每次插入时自动抓取调用栈并存入持久化日志表,完全不触碰核心业务代码:

  1. 创建持久化日志表(替代临时表t1,避免数据丢失):
CREATE TABLE insert_call_stack_log (
  log_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  call_stack CLOB,
  event_time TIMESTAMP WITH TIME ZONE,
  username VARCHAR2(128),
  inserted_row_id ROWID
);
  1. 创建触发器:
CREATE OR REPLACE TRIGGER trg_track_insert_call_stack
AFTER INSERT ON <your_target_table>
FOR EACH ROW
DECLARE
  l_depth PLS_INTEGER;
  l_call_stack CLOB := EMPTY_CLOB();
BEGIN
  l_depth := UTL_CALL_STACK.Dynamic_Depth;
  FOR i IN 1..l_depth LOOP
    l_call_stack := l_call_stack || CHR(10) || '层级 ' || i || ': ' ||
                    UTL_CALL_STACK.Owner(i) || '.' || UTL_CALL_STACK.Concat_Subprogram(i) ||
                    ' (行号 ' || UTL_CALL_STACK.Line(i) || ')';
  END LOOP;
  INSERT INTO insert_call_stack_log (call_stack, event_time, username, inserted_row_id)
  VALUES (l_call_stack, SYSTIMESTAMP, USER, :NEW.ROWID);
END;
/

该方案简单直接,对业务性能影响极小(间歇性操作几乎无感知),只要有表的触发器创建权限即可实施。

方案2:Oracle SQL跟踪+TKPROF

如果需要更全面的执行上下文信息,可启用SQL跟踪分析INSERT语句的调用链:

  1. 查询目标INSERT语句的SQL_ID:
SELECT sql_id, sql_text FROM V$SQL WHERE sql_text LIKE 'INSERT INTO <your_target_table>%';
  1. 针对该SQL_ID启用跟踪:
EXEC DBMS_MONITOR.SQL_TRACE_ENABLE(sql_id => '<your_sql_id>', waits => TRUE, binds => FALSE);
  1. 待间歇性INSERT发生后,关闭跟踪:
EXEC DBMS_MONITOR.SQL_TRACE_DISABLE(sql_id => '<your_sql_id>');
  1. 用TKPROF工具处理跟踪文件(跟踪文件路径可通过SELECT value FROM V$PARAMETER WHERE name='user_dump_dest'查询):
tkprof <trace_file_name>.trc output.txt explain=<user>/<password>

打开生成的output.txt文件,即可查看该INSERT语句的完整调用栈和执行路径。

方案3:OEM性能分析(有权限时)

如果拥有Oracle Enterprise Manager(OEM)权限,可直接在OEM性能页面定位目标表的INSERT语句,通过可视化界面查看其执行计划和调用链信息,无需编写任何代码。

内容的提问来源于stack exchange,提问作者Piyush

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:10:45