Chinaunix首页 | 论坛 | 博客
  • 博客访问: 11680279
  • 博文数量: 8065
  • 博客积分: 10002
  • 博客等级: 中将
  • 技术积分: 96708
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-16 17:06
文章分类

全部博文(8065)

文章存档

2008年(8065)

分类: 服务器与存储

2008-07-16 10:16:41

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批量处理功能,获得的性能提高还是非常明显的。

阅读(324) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~