我想知道是否有可能找出包中的哪个包或过程正在更新表?
由于某个项目被移交(移交项目的人已经离开)没有适当的文档,我们知道我们更新的数据总是回到一些奇怪的源点.
我们猜测这可能是在我们不知情的情况下运行update命令的数据库作业或调度程序.我希望有一种方法可以找出源代码调用的位置,即更新表并将源作为触发器插入到我们正在监视的表中.
有任何想法吗?
谢谢.
更新:我探讨了如何将一个语句追溯到它自己的PL/SQL对象.
结合Tony提到的内容,您可以创建一个记录表和一个如下所示的触发器:
CREATE TABLE statement_tracker
( SID NUMBER
, serial# NUMBER
, date_run DATE
, program VARCHAR2(48) null
, module VARCHAR2(48) null
, machine VARCHAR2(64) null
, osuser VARCHAR2(30) null
, sql_text CLOB null
, program_id number
);
CREATE OR REPLACE TRIGGER smb_t_t
AFTER UPDATE
ON smb_test
BEGIN
INSERT
INTO statement_tracker
SELECT ss.SID
, ss.serial#
, sysdate
, ss.program
, ss.module
, ss.machine
, ss.osuser
, sq.sql_fulltext
, sq.program_id
FROM v$session ss
, v$sql sq
WHERE ss.sql_address = sq.address
AND ss.SID = USERENV('sid');
END;
/
Run Code Online (Sandbox Code Playgroud)
为了使上面的触发器能够编译,当您以SYS用户身份登录时,您需要向触发器的所有者授予这些权限:
grant select on V_$SESSION to <user>;
grant select on V_$SQL to <user>;
Run Code Online (Sandbox Code Playgroud)
您可能希望保护触发器中的insert语句,只有在您感兴趣的更改发生时才会使其记录 - 在我的测试服务器上,此语句运行得相当慢(1秒),所以我不会我想记录所有这些更新.当然,在这种情况下,您需要将触发器更改为行级触发器,以便您可以检查:new或:old值.如果您真的担心select的开销,可以将其更改为不加入v $ sql,而只是保存SQL_ADDRESS列,然后使用DBMS_JOB计划作业,并通过第二次更新更新sql_text列语句,从而将更新卸载到另一个会话,而不是阻止您的原始更新.
不幸的是,这只会告诉你一半的故事.您将要查看的语句将是最近端的语句 - 在这种情况下是更新 - 即使由启动它的进程执行的原始语句是存储过程.这是program_id列的用武之地.如果update语句是过程或触发器的一部分,program_id将指向相关代码的object_id - 您可以这样解决它:
SELECT * FROM all_objects where object_id = <program_id>;
Run Code Online (Sandbox Code Playgroud)
在直接从客户端执行update语句的情况下,我不知道program_id代表什么,但你不需要它 - 你在statement_tracker的"program"列中有可执行文件的名称.如果更新是从匿名PL/SQL块执行的,我不是如何追踪它 - 你需要进一步试验.
但是,osuser /机器/程序/模块信息可能足以让您指向正确的方向.
| 归档时间: |
|
| 查看次数: |
9628 次 |
| 最近记录: |