11g中对于触发器部分有了一定的增强,主要表现在两个方面。一个是对触发器的触发顺序可以进行控制。另一个是可以定义一个复合触发器。
介绍一下复合触发器。复合触发器中可以包括BEFORE STATEMENT、BEFORE EACH ROW、AFTER EACH ROW和AFTER STATEMENT四个部分,将四种类型的触发器集成在一个触发器中,如果需要多个类型的触发器配合使用,采用复合触发器会显得逻辑更加清晰,而且不容易出现错误。在复合触发器中定义的变量可以在不同类型的触发语句中使用,不再需要使用外部包存储中间结果。而且利用复合触发器的批量操作还可以提高触发器的性能。
下面先看一个简单的COMPOUND TRIGGER的语法:
SQL> CREATE TABLE T (ID NUMBER, NAME VARCHAR2(30)); 表已创建。 SQL> CREATE OR REPLACE TRIGGER TRI_COMPOUND FOR INSERT OR UPDATE OR DELETE ON T 2 COMPOUND TRIGGER 3 BEFORE STATEMENT IS 4 BEGIN 5 DBMS_OUTPUT.PUT_LINE('BEFORE STATEMENT'); 6 END BEFORE STATEMENT; 7 8 BEFORE EACH ROW IS 9 BEGIN 10 DBMS_OUTPUT.PUT_LINE('BEFORE EACH ROW'); 11 END BEFORE EACH ROW; 12 13 AFTER EACH ROW IS 14 BEGIN 15 DBMS_OUTPUT.PUT_LINE('AFTER EACH ROW'); 16 END AFTER EACH ROW; 17 18 AFTER STATEMENT IS 19 BEGIN 20 DBMS_OUTPUT.PUT_LINE('AFTER STATEMENT'); 21 END AFTER STATEMENT; 22 END; 23 / 触发器已创建 SQL> SET SERVEROUT ON SQL> INSERT INTO T SELECT ROWNUM, TNAME FROM TAB; BEFORE STATEMENT BEFORE EACH ROW AFTER EACH ROW BEFORE EACH ROW AFTER EACH ROW BEFORE EACH ROW AFTER EACH ROW AFTER STATEMENT 已创建3行。
了解了COMPOUND触发器的语法,下面看看如何利用COMPOUND TRIGGER来简化变异表的处理。在以前的一篇文章中,介绍了:通过触发器复制包含LONG类型的表:http://yangtingkun.itpub.net/post/468/41936
里面包括了变异表触发器的处理方法,下面用COMPOUND TRIGGER来解决这个问题:
SQL> CREATE TABLE T_LONG (ID NUMBER PRIMARY KEY, COMMENTS LONG); 表已创建。 SQL> CREATE TABLE T_LONG_LOG (ID NUMBER PRIMARY KEY, COMMENTS CLOB); 表已创建。 SQL> CREATE OR REPLACE TRIGGER TRI_T_LONG_COMPOUND FOR INSERT ON T_LONG 2 COMPOUND TRIGGER 3 TYPE T_NUMBER IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; 4 V_ID T_NUMBER; 5 BEFORE EACH ROW IS 6 BEGIN 7 V_ID(V_ID.COUNT + 1) := :NEW.ID; 8 END BEFORE EACH ROW; 9 10 AFTER STATEMENT IS 11 BEGIN 12 FORALL I IN 1..V_ID.COUNT 13 INSERT INTO T_LONG_LOG SELECT ID, TO_LOB(COMMENTS) FROM T_LONG WHERE ID = V_ID(I); 14 END AFTER STATEMENT; 15 END; 16 / 触发器已创建 SQL> INSERT INTO T_LONG SELECT ROWNUM, TNAME FROM TAB; 已创建5行。 SQL> COL COMMENTS FORMAT A40 SQL> SELECT * FROM T_LONG; ID COMMENTS ---------- ---------------------------------------- 1 T 2 T_LONG 3 T_LONG_LOG 4 T_SESSION 5 T_SESSION_STAT SQL> SELECT * FROM T_LONG_LOG; ID COMMENTS ---------- ---------------------------------------- 1 T 2 T_LONG 3 T_LONG_LOG 4 T_SESSION 5 T_SESSION_STAT
对比一下就可以看出,使用COMPOUND触发器要比建立三个触发器加一个包要简化很多,而且初始化,处理,清除等所有的步骤都在一起,也不容易出错。
而且由于COMPOUND所有的代码可以集中在一起,现在很多操作可以批量处理,这样COMPOUND还可以提高性能。
现在仍然使用第一个例子,为T增加一张LOG表,对T表所有的INSERT都同时插入到LOG表中,对比一下COMPOUND TRIGGER和普通TRIGGER的性能差异:
SQL> CREATE TABLE T_LOG (ID NUMBER, NAME VARCHAR2(30));
表已创建。
SQL> TRUNCATE TABLE T;
表被截断。
下面建立两种不同的触发器,二者的功能一致,都是向T_LOG表中插入T表新插入的数据:
SQL> CREATE OR REPLACE TRIGGER TRI_COMPOUND FOR INSERT ON T DISABLE 2 COMPOUND TRIGGER 3 TYPE T_NUMBER IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; 4 TYPE T_VARCHAR2 IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER; 5 V_ID T_NUMBER; 6 V_NAME T_VARCHAR2; 7 AFTER EACH ROW IS 8 BEGIN 9 V_ID(V_ID.COUNT + 1) := :NEW.ID; 10 V_NAME(V_NAME.COUNT + 1) := :NEW.NAME; 11 END AFTER EACH ROW; 12 13 AFTER STATEMENT IS 14 BEGIN 15 FORALL I IN 1..V_ID.COUNT 16 INSERT INTO T_LOG VALUES (V_ID(I), V_NAME(I)); 17 END AFTER STATEMENT; 18 END; 19 / 触发器已创建 SQL> CREATE OR REPLACE TRIGGER TRI_A_EACHROW AFTER INSERT ON T 2 FOR EACH ROW DISABLE 3 BEGIN 4 INSERT INTO T_LOG VALUES (:NEW.ID, :NEW.NAME); 5 END; 6 / 触发器已创建
两个触发器都处于DISABLE状态,向T表插入数据,然后依次ENABLE其中的一个触发器,重复插入操作,对比三次的性能:
SQL> INSERT INTO T SELECT ROWNUM, OBJECT_NAME FROM DBA_OBJECTS; 已创建68345行。 SQL> TRUNCATE TABLE T; 表被截断。 SQL> SET TIMING ON SQL> INSERT INTO T SELECT ROWNUM, OBJECT_NAME FROM DBA_OBJECTS; 已创建68345行。 已用时间: 00: 00: 00.75 SQL> TRUNCATE TABLE T; 表被截断。 SQL> ALTER TRIGGER TRI_COMPOUND ENABLE; 触发器已更改 SQL> INSERT INTO T SELECT ROWNUM, OBJECT_NAME FROM DBA_OBJECTS; 已创建68345行。 已用时间: 00: 00: 05.59 SQL> TRUNCATE TABLE T; 表被截断。 SQL> TRUNCATE TABLE T_LOG; 表被截断。 SQL> ALTER TRIGGER TRI_COMPOUND DISABLE; 触发器已更改 SQL> ALTER TRIGGER TRI_A_EACHROW ENABLE; 触发器已更改 SQL> INSERT INTO T SELECT ROWNUM, OBJECT_NAME FROM DBA_OBJECTS; 已创建68345行。 已用时间: 00: 00: 17.31
第一次不记录时间,为了避免CACHE的影响,后面三次记录时间,分别对应不启用触发器、启用COMPOUND触发器和启动AFTER EACH ROW触发器三种情况。对比三次的执行时间,可以看到使用了COMPOUND的FORALL批量处理功能,获得的性能提高还是非常明显的。