如何跟踪SQL触发器?

时间:2018-06-09 12:21:50

标签: sql oracle triggers trace

我想跟踪触发器的执行但我不知道该怎么做。随着自动跟踪设置的开启,我想到的第一个想法是强制触发,但它仍然无法正常工作。 我应该如何查看触发器的执行跟踪器?

2 个答案:

答案 0 :(得分:2)

Oracle为您提供了两种跟踪PL / SQL的好方法。首选方法是使用DBMS_HPROF包。不太好(比较旧)是DBMS_PROFILER。

由于DBMS_PROFILER更简单且您的要求很简单,我将证明这一点。

首先,让我们创建一个带有触发器的表:

CREATE TABLE matt_test1 ( a number );

CREATE TRIGGER matt_trg1 BEFORE INSERT ON matt_test1 FOR EACH ROW
BEGIN
  NULL;
END;

接下来,我们启动探查器,运行INSERT(应触发我们的触发器),然后停止探查器:

EXEC DBMS_PROFILER.START_PROFILER;

INSERT INTO matt_test1 (a) values (1);

EXEC DBMS_PROFILER.STOP_PROFILER;

现在,有更好的方法来启动和停止探查器。这些方法将返回使用的运行ID,您将需要它来查询结果。在我们的快速和肮脏的示例中,我们将只查看最新的分析器结果:

SELECT * FROM plsql_profiler_runs order by runid desc;

在我的系统上,那是runid 2。

接下来,我们查询PLSQL_PROFILER*表以获取有关在运行期间执行的PL / SQL的所有信息。这不会只列出触发器 - 它会更多:几乎所有从PL / SQL调用的SQL语句以及从PL / SQL调用的任何其他PL / SQL块(过程或函数)。

以下是我以前使用的查询(在我切换到使用DBMS_HPROF之前:

SELECT   d.runid,
         u.unit_type,
         u.unit_owner,
         u.unit_name,
         d.line#,
         d.total_occur,
         d.total_time / POWER (10, 9) total_seconds,
         d.min_time / POWER (10, 9) min_seconds,
         d.max_time / POWER (10, 9) max_seconds,
         ss.source line_text,
         SUM (d.total_time / POWER (10, 9)) OVER (PARTITION BY NULL ORDER BY d.total_time DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
                                                                                                               cumulative_seconds,
         SUM (d.total_time / POWER (10, 9)) OVER (PARTITION BY NULL) elapsed_seconds_for_run
FROM     plsql_profiler_data d INNER JOIN plsql_profiler_units u ON u.runid = d.runid
         AND                                                       u.unit_number = d.unit_number
         LEFT JOIN SYS.user$ su ON su.NAME = u.unit_owner
         LEFT JOIN SYS.obj$ so
         ON  so.NAME = u.unit_name
         AND so.owner# = su.user#
         AND DECODE (so.type#,
                     7, 'PROCEDURE',
                     8, 'FUNCTION',
                     9, 'PACKAGE',
                     11, 'PACKAGE BODY',
                     12, 'TRIGGER',
                     13, 'TYPE',
                     14, 'TYPE BODY',
                     'UNDEFINED') = u.unit_type
         LEFT JOIN SYS.source$ ss ON ss.obj# = so.obj#
         AND                        ss.line = d.line#
WHERE    1=1
and d.runid = 2
AND      d.total_occur > 0
ORDER BY d.total_time DESC;

最后,结果:

+-------+-----------------+-------------+-------------+-------+-------------+---------------+-------------+-------------+-----------+--------------------+-------------------------+
| RUNID |    UNIT_TYPE    | UNIT_OWNER  |  UNIT_NAME  | LINE# | TOTAL_OCCUR | TOTAL_SECONDS | MIN_SECONDS | MAX_SECONDS | LINE_TEXT | CUMULATIVE_SECONDS | ELAPSED_SECONDS_FOR_RUN |
+-------+-----------------+-------------+-------------+-------+-------------+---------------+-------------+-------------+-----------+--------------------+-------------------------+
|     2 | ANONYMOUS BLOCK | <anonymous> | <anonymous> |     1 |           2 |   0.000010001 |    0.000001 | 0.000008001 |           |        0.000010001 |             0.000013001 |
|     2 | TRIGGER         | APPS        | MATT_TRG1   |     2 |           1 |      0.000002 |    0.000002 |    0.000002 | BEGIN     |        0.000012001 |             0.000013001 |
|     2 | ANONYMOUS BLOCK | <anonymous> | <anonymous> |     1 |           1 |      0.000001 |    0.000001 |    0.000001 |           |        0.000013001 |             0.000013001 |
+-------+-----------------+-------------+-------------+-------+-------------+---------------+-------------+-------------+-----------+--------------------+-------------------------+

您可以看到我们的触发器在上面第2行中被触发。

答案 1 :(得分:1)

想到两种方式:

如果您可以更改触发器代码,请创建一个日志表并从触发器主体向其写入调试消息:

CREATE TABLE trigger_log (t TIMESTAMP, m VARCHAR2(4000));

CREATE OR REPLACE my_trigger BEFORE INSERT ...
BEGIN 
  INSERT INTO trigger_log(t, m)
  VALUES (systimestamp,'my_trigger fired :new_id is='||:new_id);

  ... rest of trigger body ...
END;
/

其次,如果您可以更改审核设置,请启用相关表的审核。