C、 事务日志满场景二:某个事务一直未提交,占用的日志不能被重用,导致日志满
现在看另外一个场景,我在一个会话中执行了如下命令:
C:\Documents and Settings\administrator>db2 +c call proc_testlog(3)
SQL0964C 数据库的事务日志已满。 SQLSTATE=57011
显然,数据库日志已满,于是,根据上面的方法,我找是哪个事务占用了日志。
Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:10:12
Transactions:
Address AppHandl [nod-index] TranHdl Locks State Tflag Tflag2
Firstlsn Lastlsn LogSpace SpaceReserved TID
AxRegCnt GXID
0x7FC21A80 12 [000-00012] 2 7 READ 0x00000000 0x00000
000 0x000000000000 0x000000000000 0 0 0x0000000053A9
1 0
0x7FC22780 13 [000-00013] 3 0 READ 0x00000000 0x00000
000 0x000000000000 0x000000000000 0 0 0x00000000538F
1 0
0x7FC23480 14 [000-00014] 4 0 READ 0x00000000 0x00000
000 0x000000000000 0x000000000000 0 0 0x0000000053BE
1 0
0x7FC24180 15 [000-00015] 5 0 READ 0x00000000 0x00000
000 0x000000000000 0x000000000000 0 0 0x000000005391
1 0
0x7FC24E80 16 [000-00016] 6 0 READ 0x00000000 0x00000
000 0x000000000000 0x000000000000 0 0 0x000000005394
1 0
0x7FC25B80 17 [000-00017] 7 4 WRITE 0x00000000 0x00000
000 0x0000538A93B7 0x0000538A9455 184 408 0x00000000539A
很奇怪,从结果显示,我没有发现任何一个占用大量日志的应用程序,日志的使用显然都非常的小,那为什么日志还会满呢?我们再注意下占用日志的应用,查看下各自使用的日志文件。
Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:12:34
Logs:
Current Log Number 4
Pages Written 9498
Method 1 Archive Status n/a
Method 1 Next Log to Archive n/a
Method 1 First Failure n/a
Method 2 Archive Status n/a
Method 2 Next Log to Archive n/a
Method 2 First Failure n/a
Address StartLSN State Size Pages Filename
0x7FBECBD4 0x0000537F0000 0x00000000 10000 10000 S0000000.LOG
0x7FBECC74 0x000055F00000 0x00000000 10000 10000 S0000001.LOG
0x7FBECD14 0x000058610000 0x00000000 10000 10000 S0000002.LOG
0x7EABB2F4 0x00005AD20000 0x00000000 10000 10000 S0000003.LOG
0x7EABB394 0x00005D430000 0x00000000 10000 10000 S0000004.LOG
分析发现,这个占用日志的应用的日志开始lsn为0x0000538A93B7,结束lsn为0x0000538A9455,正好落在第一日志文件中,因为这个事务一直没有被提交,所以S0000000.LOG一直不能被重用,这样业务在将主日志和辅助日志用完后,无法重新开始使用日志文件,导致出现日志满的错误。同样,使用上面的方法,我们可以查找出这个Applications handle为7的一直没有提交的小事务执行的是什么操作。
上面的情况模拟方法:
在一个回话中执行一个小事物,比如
C:\Documents and Settings\administrator>db2 +c "insert into test values ( 1112,1, ’sdfsdfsdfsdf’ , ’sdfsdfsdfsdfsdf’ , ’sdfsdfsdffsdfsd’ )
在另外一个回话中执行占用事务比较大的操作,比如:db2 call proc_testlog(300000),在这个回话中的操作都及时提交,直到配置的日志文件被使用完,再执行小操作db2 call proc_testlog(3),就可以出现上面的日志满的情况。
解决方案:
可以看出,不是日志满的问题一定是由于应用占用大量的日志导致的,一个被忽略的未提交的操作也可能导致系统的日志无法被重用而导致日志满,在应用中,这是我们应该尽量避免的。但是总是如果无法保证所有的操作都及时的提交,我们可以设置num_log_span参数来规避这个问题,参数指定是否对一个事务可以跨越多少个日志文件具有限制以及该限制是多少,当设置这个参数后,未提交的事务所在的日志与当前日志跨越的个数超过这个值,将被中断,从而避免事务长时间存在导致系统日志满。另外大事务可以跨越的日志也不能超过这个限制,所以当设置max_log和num_log_span后,一个事务所可以使用的事务日志将取2者中比较小的值。
当启用了无限活动日志空间时,max_log和 num_log_span 配置参数非常有用。如果打开了无限记录(即,logsecondary 为 -1),那么事务数不受日志文件数的上限(logprimary + logsecond)限制。当到达 logprimary 的值时,DB2 将开始归档活动日志,而不是使事务失败。这样可能会导致问题,例如,有一个长期运行的事务,但一直未落实它(可能是由于应用程序不正确导致的)。如果出现这种情况,那么活动日志空间会不断增长,从而可能使得崩溃恢复性能很差。为了防止这样,可以为 max_log 和/或 num_log_span 配置参数指定值。
注意:系统临时表的使用,系统临时表的数据操作是不记日志的,但是表的定义是有少量日志记录的,所以,临时表定义了一直没操作,不提交也可能会引起部分小日志的一直被占用。