技术开发 频道

DB2数据库发生死锁了怎么办?


如果发生死锁或锁等待等现象我们该怎么办

    一旦我们在上述的2,3项发现了死锁或锁等待或锁升级,或者其他途径报告锁的问题,我们将如何解决呢?

首先我们要考虑应用系统的变化
    考察最近是否有新的程序加入或者是否对现系统做了改动,比如表结构变了,程序变了,是否有了大量数据的变动。
如果有,可以重新编译与变动相关的程序(比如存储过程等),查看与变动相关的SQL(比如运行效率低)。

其次我们可以使用DB2提供工具来解决问题
    如果上述方法还无法解决问题,就要采用DB2提供的工具来尝试解决问题了。
1. 查看db2diag.log文件,查找sqlcode是 -911或 -952

2006-11-08-16.29.11.398155+480 E36235682A521 LEVEL: Error PID : 12979 TID : 1 PROC : db2agent (TESTDB) 0 INSTANCE: db2inst1 NODE : 000 DB : TESTDB APPHDL : 0-288 APPID: 198.132.3.100.57177.061108070923 AUTHID : TESTDB FUNCTION: DB2 UDB, data management, sqldEscalateLocks, probe:4 MESSAGE : ADM5503E The escalation of "2" locks on table“TESTDB.TEST12" to lock intent "X" has failed.
The SQLCODE is "-911". 2006-11-08-16.24.39.672914+480 E36100838A502 LEVEL: Error PID : 20866 TID : 1 PROC : db2agent (TESTDB) 0 INSTANCE: db2inst1 NODE : 000 DB : TESTDB APPHDL : 0-1394 APPID: 198.132.3.110.58426.061108075556 AUTHID : TESTDB FUNCTION: DB2 UDB, data management, sqldEscalateLocks, probe:4 MESSAGE : ADM5503E The escalation of "1" locks on table “TESTDB.TEST11"to lock intent "X" has failed.
The SQLCODE is "-952".

    我们可以看到红字标识出的SQLCODE is  "-911" 或 SQLCODE is "-952"的信息里,也分别提供了的表名字(TESTDB.TEST12,TESTDB.TEST11),从这里我们可以看出,锁的问题与这些表相关,有了这些表的描述,对我们定位问题就前进了一步,下面我们需要定位是哪个程序或哪个SQL影响的,


2. 锁的快照信息(snapshot)
    当使用list applications命令还能看到运行状态还是锁定等待的应用时,可以立即使用get snapshot for locks 命令来查找到底锁定是被哪个程序挂起的
    查看应用程序的状态是否有锁定等待(Lock-wait)状态出现
    执行命令  list applications for db sample show detail 得到如下结果

    。。。。。。。。
应用程序句柄                               = 54
应用程序标识                        = *LOCAL.DB2.071129094306
序号                                = 00001
应用程序名                          = db2bp.exe CONNECT
授权标识                    = DB2ADMIN
应用程序状态                        = 锁定等待
状态更改时间                        = 2007-11-29 17:50:16.124739
应用程序代码页                      = 1386
挂起的锁定                          = 4
总计等待时间(毫秒)                = 237867
  挂起锁定的代理程序标识                   = 45  
保留锁定的应用程序标识                   = *LOCAL.DB2.071129094146  
锁定名称                                = 0x030006000500C0020000000052  
锁定属性                                 = 0x00000000  
发行版标志                               = 0x00000001  
锁定对象类型                             = 行  
锁定方式                                 = 互斥锁定(X)  
请求的锁定方式                           = 下一个键共享(NS)  
挂起锁定的表空间名                       = IBMDB2SAMPLEREL  
挂起锁定的表模式                         = DB2ADMIN  
挂起锁定的表名                           = TEST1  
挂起锁定的表的数据分区标识               = 0  
锁定等待启动时间戳记                     = 2007-11-29 17:50:16.124744 。。。。。。。。

    这里我们可以看到应用程序(54)正在等待应用程序(45)的锁的释放,被锁的的表名是 DB2ADMIN.TEST1。

3. 应用程序和动态SQL的快照信息(snapshot)
    当使用list applications命令已经不能看到运行状态是锁定等待的应用时,就无法立即定位是哪个应用程序锁定引起的,这时我们使用get snapshot for applications和 get snapshot for dynamic sql 命令来查找锁定可能是被哪个SQL或哪个程序引起的,比如得到如下内容:

            应用程序快照

应用程序句柄                               = 45
。。。。。。。。。。。。。。

已用的 UOW 日志空间(以字节计)            = 174
先前的 UOW 完成时间戳记                    = 2007-11-29 17:41:46.288856
上次完成 uow 耗用时间(秒.毫秒)           = 0.000000
UOW 启动时间戳记                           = 2007-11-29 17:41:58.733755
UOW 停止时间戳记                           =
UOW 完成状态                               = 。。。。。。。。。。。。。

    这里我们可以看到红字标识部分的应用程序(45),已经执行很长时间但一直没有结束,说明有可能就是这个程序造成的。

      动态 SQL 快照结果
 数据库名称                               = SAMPLE
 数据库路径                      = C:\DB2\NODE0000\SQL00001\
执行数                          = 17
编译数                          = 1
最差预编译时间(毫秒)          = 9
非常好的预编译时间(毫秒)          = 9
已删除的内部行                  = 0
已插入的内部行                  = 0
已读取的行                      = 0
已更新的内部行                  = 0
已写入的行                      = 0
语句排序                        = 17
语句排序溢出                    = 0
总计排序时间                    = 3
缓冲池数据逻辑读取              = 0
缓冲池数据物理读取              = 0
缓冲池临时数据逻辑读取          = 0
缓冲池临时数据物理读取          = 0
缓冲池索引逻辑读取              = 0
缓冲池索引物理读取              = 0
缓冲池临时索引逻辑读取          = 0
缓冲池临时索引物理读取          = 0
缓冲池 xda 逻辑读取             = 0
缓冲池 xda 物理读取             = 0
缓冲池临时 xda 逻辑读取         = 0
缓冲池临时 xda 物理读取         = 0
总计执行时间(秒.毫秒)         = 0.057497
总计用户 CPU 时间(秒.毫秒)    = 0.000000
总计系统 CPU 时间(秒.毫秒)    = 0.000000
语句文本                      = SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, CASE TABLE_TYPE WHEN 'NICKNAME' THEN 'SYNONYM' ELSE TABLE_TYPE END as TABLE_TYPE, REMARKS  FROM DB2ADMIN.TEST11 WHERE TABLE_SCHEM = 'DB2ADMIN' AND TABLE_TYPE IN ('TABLE') ORDER BY 4,1,2,3

    这里我们假设在db2diag.log里报出的是表DB2ADMIN.TEST11发生锁问题,那么就找根此表相关的SQL语句,比如红字标识出的SQL语句,通过这些SQL来定位最终是由于哪个应用程序或SQL造成的锁定。

4. DB2PD程序快速定位锁定SQL语句
    当使用list applications命令还能看到运行状态还是锁定等待的应用时,可以立即使用db2pd 命令来查找到底锁定是被哪个程序哪个SQL语句挂起的。从版本 8.2.2开始DB2也可以使用 db2pd 命令来获取死锁信息。
    我们用如下命令生成锁定信息,生成的信息存入locklog 文件内
db2pd -db sample -locks -transactions –applications -dynamic -file locklog

    我们会在文件中看到锁

Locks: Address TranHdl Lockname Type Mode Sts Owner Dur HoldCount Att ReleaseFlg 0x7F890990 2 03000500040080020000000052 Row ..X G 2 1 0 0x08 0x40000000 0x7F890D80 7 03000500040080020000000052 Row .NS W 0 1 0 0x00 0x00000001

    从中会发现 TranHdl 7 正在等待 TranHdl 2 挂起的锁定,他们共同要求锁定名称相同(03000500040080020000000052)。

    下面我们找跟TranHdl 相关的AppHandl

Transactions: Address AppHandl [nod-index] TranHdl Locks State Tflag Tflag2 Firstlsn Lastlsn LogSpace SpaceReserved TID AxRegCnt GXID 0x7FC21A80 20 [000-00020] 2 4 WRITE 0x00000000 0x00000000 0x000003A9A957 0x000003ACD1FD 154 282 0x000000001345 1 0 0x7FC25B80 25 [000-00025] 7 4 READ 0x00000000 0x00000000 0x000000000000 0x000000000000 0 0 0x000000001672 1 0

    从中会发现TranHdl 2,7对应的AppHandl 是 20,25

    然后我们再查找AppHandl20,25对应的动态 SQL 语句的当前和最后一个锚点标识和语句唯一标识(C-AnchID C-StmtUID  L-AnchID L-StmtUID)。
    这允许直接从应用程序映射至动态 SQL 语句。

Applications: Address AppHandl [nod-index] NumAgents CoorEDUID Status C-AnchID C-StmtUID L-AnchID L-StmtUID Appid WorkloadID WorkloadOccID 0x7AEFBF30 25 [000-00025] 1 396 Lock-wait 116 1 116 1 *LOCAL.DB2.071127074823 1 2 0x7AED8080 20 [000-00020] 1 420 UOW-Waiting 0 0 13 1 *LOCAL.DB2.071127074818 1 1

    其中AppHandl 20对应的C-AnchID C-StmtUID  L-AnchID L-StmtUID 是 0, 0, 13 , 1
    AppHandl 25对应的C-AnchID C-StmtUID  L-AnchID L-StmtUID 是 116, 1, 116 , 1
    这里我只需要关注AppHandl 20对应的 ID

    最后我们再查找C-AnchID C-StmtUID  L-AnchID L-StmtUID 对应的sql语句

Dynamic SQL Statements: Address AnchID StmtUID NumEnv NumVar NumRef NumExe Text
0x7EA75AE0 13 1 1 1 1 1 insert into test1 values(2,'test1')

    完成上面过程我们发现了是insert into test1 values(1,'test1') sql导致了死锁或锁超时,因为test1表就是锁定超时报告文件中检测出来的锁定表。

    但需要注意的是,当前发现的sql语句  insert into test1 values(2,'test1') 是在其应用程序没有后续的其他sql语句发生时找到的结果,在实际的程序中在insert into test1 values(2,'test1') 语句后面很有可能会有其他sql语句执行,而在db2pd跟踪中Applications所能反应的只能是当前执行的sql语句和上一个执行的sql语句,这两个sql语句,不一定涉及到锁定超时报告文件当中的test1表,所以需要你在db2pd的检测文件仔细查找跟test1表相关的sql语句。

0
相关文章