触发器(TRIGGER)对DB2数据库系统性能的影响

本文探讨了DB2数据库中触发器(TRIGGER)对性能的影响,通过测试发现,即使空触发器也会增加30%左右的操作时间,而执行复杂逻辑的触发器可能导致性能下降130%以上,建议在高性能应用中谨慎使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

触发器(TRIGGER)对DB2数据库系统性能的影响

摘要:触发器(TRIGGER)是DB2数据库系统的一个重要特性。触发器是一种特殊的存储过程,它在插入(INSERT),删除(DELETE)或更新(UPDATE)特定表中的数据时触发执行一系列SQL操作,它比DB2数据库本身标准的功能有更精细和更复杂的数据控制能力。触发器对数据库系统的性能有什么样的影响呢?本文就针对触发器对DB2数据库系统性能的影响进行了测试和比较。

前言:

触发器(TRIGGER)是DB2数据库系统的一个重要特性。触发器(TRIGGER)是一种用户定义的特殊的存储过程,它在插入(INSERT),删除(DELETE)或更新(UPDATE)特定表中的数据时触发执行一系列用户定义的SQL操作,它比数据库本身标准的功能有更精细和更复杂的数据控制能力。因此触发器(TRIGGER)实际上是用户的数据库应用(APPLICATION)的一部分。

利用触发器(TRIGGER),用户可以实现复杂的业务逻辑,例如:

1.   可以利用触发器(TRIGGER)基于数据库的值赋予用户具有操作数据库的某种权利。

2.   可以利用触发器(TRIGGER)基于时间限制用户的操作,例如不允许下班后和节假日修改数据库数据。

3.   可以利用触发器(TRIGGER)基于数据库中的数据限制用户的操作,例如不允许价格的升幅一次超过10%。

4.   审计。可以利用触发器(TRIGGER)跟踪用户对数据库的操作。例如审计用户操作数据库的语句并且把用户对数据库的更新写入审计表。

5.   可以利用触发器(TRIGGER)实现复杂的数据完整性规则。实现非标准的数据完整性检查和约束。触发器可产生比规则更为复杂的限制。与规则不同,触发器可以引用列或数据库对象。例如,触发器可回退任何企图吃进超过自己保证金的期货。

6.   可以利用触发器(TRIGGER)提供可变的缺省值。

7.   可以利用触发器(TRIGGER)实现复杂的非标准的数据库相关完整性规则。触发器可以对数据库中相关的表进行连环更新。

8.   可以利用触发器(TRIGGER)同步实时地复制表中的数据。

9.   可以利用触发器(TRIGGER)自动计算数据值,如果数据的值达到了一定的要求,则进行特定的处理。例如,如果公司的帐号上的资金低于5万元则立即给财务人员发送警告数据。

触发器(TRIGGER)带给了DB2数据库应用开发巨大的便利, 使用户可以自己定制针对特定表的插入(INSERT),删除(DELETE)或更新(UPDATE)操作。但是, 触发器(TRIGGER)的存在使原本简单的插入(INSERT)、删除(DELETE)和更新(UPDATE)操作变得复杂, 因此我们在享受触发器(TRIGGER)带给我们的便利的时候, 也不得不面对触发器带给数据库系统的性能损失。

本文就针对触发器对DB2数据库系统性能的影响进行了测试和比较。

测试步骤:

在定义了触发器(TRIGGER)后, DB2数据库系统在执行完每一次的插入(INSERT)、删除(DELETE)或者更新(UPDATE)操作之后, 都要执行响应的触发器(TRIGGER)。 因此,触发器对数据库系统性能的影响来自于两个方面:

1.   初始化触发器运行上下文(CONTEXT)需要的时间;

2.   执行触发器(TRIGGER)中定义的SQL语句需要的时间。

笔者设计了以下测试步骤来测试以上两种因素对DB2数据库系统性能的影响。

1. 测试准备:创建表和触发器(TRIGGER

笔者创建了4张结构相同表SRCTB,TB1 TB2,和TB3 3张表的定义如下:

CREATE TABLE SRCTB (A INTEGER, B INTEGER);

CREATE TABLE TB1 (A INTEGER, B INTEGER);

CREATE TABLE TB2 (A INTEGER, B INTEGER);

CREATE TABLE TB3 (A INTEGER, B INTEGER);

创建一个源数据表SRCTB,这个表和表TB1TB2TB3结构相同,在这个表中存有1000000条数据, 创建这个表是为了在测试中向表TB1TB2TB3中一次性插入1000000条数据。

为了测试和比较触发器(TRIGGER)对DB2数据库系统性能的影响, 笔者设计了以下测试环境:

1.     在表TB1上不定义触发器(TRIGGER);

2.     在表TB2上定义3个空(DUMMY)触发器,即这个触发器不执行任何SQL语句,这3个触发器分别是插入(INSERT)触发器、删除(DELETE)触发器 和更新(UPDATE)触发器;

3.     在表TB3上定义3个触发器,这3个触发器分别是插入(INSERT)触发器、删除(DELETE)触发器 和更新(UPDATE)触发器,这些触发器只用来执行一个简单的SQL语句, 把相应的数据存储到一个日志表(LOGTB)中。

创建脚本如下:

1.       创建源数据表(SRCTB)的脚本CREATE_SRCTB.SQL内容如下:

--清单1 CREATE_SRCTB.SQL

CONNECT TO TESTTRG;

CREATE TABLE SRCTB (A INTEGER, B INTEGER);

CREATE INDEX ISRCTB ON SRCTB (A,B);

DISCONNECT TESTTRG;

2.       创建测试环境, 包括表TB1TB2TB3和相应的触发器(TRIGGER),创建脚本CREATE_TEST_ENV.SQL内容如下:

--清单2 CREATE_TEST_ENV.SQL

CONNECT TO TESTTRG;

CREATE TABLE TB1 (A INTEGER, B INTEGER);

CREATE TABLE TB2 (A INTEGER, B INTEGER);

CREATE TABLE TB3 (A INTEGER, B INTEGER);

--LOGTB是日志表--

CREATE TABLE LOGTB (A INTEGER, B INTEGER);

CREATE TRIGGER TESTTRG1 AFTER INSERT ON TB2 REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL BEGIN ATOMIC END;

CREATE TRIGGER TESTTRG2 AFTER UPDATE ON TB2 REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL BEGIN ATOMIC END;

CREATE TRIGGER TESTTRG3 AFTER DELETE ON TB2 REFERENCING OLD AS O FOR EACH ROW MODE DB2SQL BEGIN ATOMIC END;

CREATE TRIGGER TESTTRG4 AFTER INSERT ON TB3 REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO LOGTB (A,B) VALUES (N.A, N.B); END;

CREATE TRIGGER TESTTRG5 AFTER UPDATE ON TB3 REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO LOGTB (A,B) VALUES (N.A, N.B); END;

CREATE TRIGGER TESTTRG6 AFTER DELETE ON TB3 REFERENCING OLD AS O FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO LOGTB (A,B) VALUES (O.A, O.B); END;

DISCONNECT TESTTRG;

3.       销毁测试环境脚本DESTROY_TEST_ENV.SQL脚本如下:

--清单3 DESTROY_TEST_ENV.SQL

CONNECT TO TESTTRG;

DROP TRIGGER TESTTRG1;

DROP TRIGGER TESTTRG2;

DROP TRIGGER TESTTRG3;

DROP TRIGGER TESTTRG4;

DROP TRIGGER TESTTRG5;

DROP TRIGGER TESTTRG6;

DROP TABLE LOGTB;

DROP TABLE TB3;

DROP TABLE TB2;

DROP TABLE TB1;

DISCONNECT TESTTRG;

2. 测试:分别在表TB1TB2TB3上执行插入(INSERT)、更新(UPDATE)和删除(DELETE)操作

测试名称

测试内容

TEST1

执行SQL语句,向表TB1中插入1,000,000条数据,并记录SQL语句执行的时间

TEST2

执行SQL语句,更新表TB1中的这1,000,000条数据,并记录SQL语句执行的时间

TEST3

执行SQL语句,删除表TB1中的这1,000,000条数据,并记录SQL语句执行的时间

TEST4

执行SQL语句,向表TB2中插入1,000,000条数据,记录SQL语句执行的时间,并与TEST1中的结果比较

TEST5

执行SQL语句,更新表TB2中的这1,000,000条数据,记录SQL语句执行的时间,并与TEST2中的结果比较

TEST6

执行SQL语句,删除表TB2中的这1,000,000条数据,记录SQL语句执行的时间,并与TEST3中的结果比较

TEST7

执行SQL语句,向表TB3中插入1,000,000条数据,记录SQL语句执行的时间,并与TEST1中的结果比较

TEST8

执行SQL语句,更新表TB3中的这1,000,000条数据,记录SQL语句执行的时间,并与TEST2中的结果比较

TEST9

执行SQL语句,删除表TB3中的这1,000,000条数据,记录SQL语句执行的时间,并与TEST3中的结果比较

由于表TB1上没有定义触发器(TRIGGER),因此TEST1TEST2TEST3的测试结果是后面测试的基准。

TB2上定义的插入(INSERT)、更新(UPDATE)、删除(DELETE)为空(DUMMY)触发器, 因此TEST4TEST5TEST6的目的是测试初始化触发器运行上下文(CONTEXT)对DB2数据库系统性能的影响。

TB3上定义的插入(INSERT)、更新(UPDATE)、删除(DELETE)为一个简单的触发器, 因此TEST7TEST8TEST9的目的是测试触发器对DB2数据库系统性能的影响。

在测试过程中, 笔者适用DB2数据库系统提供的GET SNAPSHOT语句来记录SQL语句的运行时间:

UPDATE MONITOR SWITCHES USING STATEMENT ON;

GET SNAPSHOT FOR DYNAMIC SQL ON <DATABASE>

 

测试脚本如下

1.       针对表TB1进行插入(INSERT)测试的脚本TEST1.SQL内容如下:

--清单4 TEST1.SQL

CONNECT TO TESTTRG;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

INSERT INTO TB1 (A,B) SELECT A,B FROM SRCTB;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

DISCONNECT TESTTRG;

2.       针对表TB1进行更新(UPDATE)测试的脚本TEST2.SQL的内容如下:

--清单5 TEST2.SQL

CONNECT TO TESTTRG;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

UPDATE TB1 SET B=-1;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

DISCONNECT TESTTRG;

3.       针对表TB1进行删除(DELETE)测试的脚本TEST3.SQL内容如下:

--清单6 TEST3.SQL

CONNECT TO TESTTRG;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

DELETE FROM TB1;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

DISCONNECT TESTTRG;

6. 针对表TB2进行插入(INSERT)测试的脚本TEST4.SQL内容如下:

--清单7 TEST4.SQL

CONNECT TO TESTTRG;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

INSERT INTO TB2 (A,B) SELECT A,B FROM SRCTB;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

DISCONNECT TESTTRG;

 

7.       针对表TB2进行更新(UPDATE)测试的脚本TEST5.SQL内容如下:

--清单8 TEST5.SQL

CONNECT TO TESTTRG;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

UPDATE TB2 SET B=-1;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

DISCONNECT TESTTRG;

8.       针对表TB2进行删除(DELETE)测试的脚本TEST6.SQL内容如下:

--清单9 TEST6.SQL

CONNECT TO TESTTRG;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

DELETE FROM TB2;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

DISCONNECT TESTTRG;

9.       针对表TB3进行插入(INSERT)测试的脚本TEST7.SQL内容如下:

--清单10 TEST7.SQL

CONNECT TO TESTTRG;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

INSERT INTO TB3 (A,B) SELECT A,B FROM SRCTB;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

SELECT COUNT(*) FROM LOGTB;

DISCONNECT TESTTRG;

10. 针对表TB3进行更新(UPDATE)测试的脚本TEST8.SQL的内容如下:

--清单11 TEST8.SQL

CONNECT TO TESTTRG;

DELETE FROM LOGTB;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

UPDATE TB3 SET B=-1;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

SELECT COUNT (*) FROM LOGTB;

DISCONNECT TESTTRG;

11. 针对表TB3进行删除(DELETE)测试的脚本TEST9.SQL内容如下:

清单12 TEST9.SQL

CONNECT TO TESTTRG;

DELETE FROM LOGTB;

UPDATE MONITOR SWITCHES USING STATEMENT ON;

DELETE FROM TB3;

GET SNAPSHOT FOR DYNAMIC SQL ON TESTTRG;

SELECT COUNT(*) FROM LOGTB;

DISCONNECT TESTTRG;

综上所述,执行一次完整的测试的过程如下:

清单13 RUN_TEST.SH

DB2 -TVF CREATE_TEST_ENV.SQL

DB2 -TVF TEST1.SQL > TEST1_RESULT.TXT

DB2 -TVF TEST2.SQL > TEST2_RESULT.TXT

DB2 -TVF TEST3.SQL > TEST3_RESULT.TXT

DB2 -TVF TEST4.SQL > TEST4_RESULT.TXT

DB2 -TVF TEST5.SQL > TEST5_RESULT.TXT

DB2 -TVF TEST6.SQL > TEST6_RESULT.TXT

DB2 -TVF TEST7.SQL > TEST7_RESULT.TXT

DB2 -TVF TEST8.SQL > TEST8_RESULT.TXT

DB2 -TVF TEST9.SQL > TEST9_RESULT.TXT

DB2 -TVF DESTROY_TEST_ENV.SQL

3. 测试结果

笔者的测试环境为:

CPU INTEL PENTIUM(R) 4 CPU 3.20GHZ

内存: 2G

硬盘: 120G

操作系统:REDHAT ENTERPRISE LINUX 4 UPDATE 4

DB2数据库系统版本为:DB2 V9.1.0.0 FOR LINUX

测试结果为:

 

TB1

TB2

TB3

 

性能损失

 

性能损失

插入(INSERT

执行时间(秒)

8.763309

11.446719

30.6%

21.071327

140.4%

用户CPU时间(秒)

3.050000

6.573333

115.5%

11.080000

263.2%

系统CPU时间(秒)

0.100000

0.116667

16.7%

0.203333

120.3%

更新(UPDATE

执行时间(秒)

6.409958

8.928048

39.3%

20.508765

221.2%

用户CPU时间(秒)

2.393333

5.290000

120.4%

11.506667

380.8%

系统CPU时间(秒)

0.093333

0.103333

10.7%

0.206667

121.4%

删除(DELETE

执行时间(秒)

8.487340

10.503482

23.8%

21.931643

158.4%

用户CPU时间(秒)

3.413333

5.433333

59.1%

11.216667

228.6%

系统CPU时间(秒)

0.100000

0.090000

-10%

0.196667

96.7%

从测试结果来看, 触发器(TRIGGER)对DB2数据库系统的性能的影响还是很大的,空(DUMMY)触发器使插入(INSERT)、更新(UPDATE)、删除(DELETESQL语句的执行时间增加了30%左右;如果触发器(TRIGGER)中还定义了其他的SQL语句,触发器使插入(INSERT)、更新(UPDATE)、删除(DELETESQL语句的执行时间增加了130%以上。

结论

在本文的测试用例中, 笔者创建的触发器(TRIGGER)比较简单。 然而实际的情况可能更要糟糕,在复杂的DB2数据库应用中,往往需要创建执行复杂逻辑的触发器(TRIGGER),在触发器执行的SQL语句可能会导致更严重的性能下降,例如这些SQL语句需要执行更长的时间, 或者这些SQL语言要锁住更多的资源,甚至造成死锁(DEADLOCK)。

综上所述, 在对性能要求较高DB2数据库应用中, 要尽可能的避免使用触发器(TRIGGER),在设计触发器的时候, 要使触发器尽可能的简单。

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值