在处理一起普通的Db2锁超时事件时,发现Locker owner是一个load作业,hold住锁的类型为Z锁。由于Load采用的是’insert into xxx allow read access’,正常情况下是不应该hold住Z锁这么长时间。遂对该问题进行了深入研究,最后发现是load commit阶段时间过长导致的。
该问题发生时,会有以下现象
1. db2 list utilities显示并没有load作业在进行
db2test@host01:~ db2 list utilities show detail
SQL1611W No data was returned by Database System Monitor. SQLSTATE=00000
2. stack
load作业的stack如下,显示在PurgeObject
<StackTrace>-----FUNC-ADDR---- ------FUNCTION + OFFSET------
0x00007F91E3B3A143 _ZN17SQLO_SLATCH_CAS6431attemptSeizeForStarvationPolicyEmmbmP28OSS_SPIN_CONFLICT_MONITORING
0x00007F91E3BBB06F _Z20sqlbPurgeObjectLocal
0x00007F91E3BBA4A2 _Z15sqlbPurgeObject
0x00007F91E7287A37 _Z22sqluCheckObjectForRedo
0x00007F91E7283D41 _Z30sqlu_process_pending_operation
0x00007F91E6BB928C _Z8sqlptppl
0x00007F91E6BAC496 _Z8sqlpxcm1
0x00007F91E6D76257 _Z12sqlrrcom_dps
0x00007F91E6D721F2 _Z8sqlrrcom
0x00007F91E6D610D8 _Z12sqlrr_commit
0x00007F91E719840D _Z12sqluv_commit
0x00007F91E7192E2A _Z24sqlu_register_table_load
0x00007F91E71853DD _Z17sqluvtld_route_in
0x00007F91E5B451E9 _Z8sqlesrvr
...
</StackTrace>
3. latch
db2test@host01:~> db2pd -latches
Latches:
Address Holder Waiter Filename LOC LatchType HoldCount
0x00007F9064109C00 586 0 Unknown 13877 SQLO_LT_SQLB_BufferPool__prevBPDCachingLatch 1
0x00007F9063F20438 586 0 Unknown 163 SQLO_LT_SQLP_SAVEPOINTS__spLatch 1
4. application status
load应用的application status是Commit Active
5. db2diag.log
db2diag.log中显示load的进展为” Completed LOAD phase”
PID : xxxx TID : xxxxxxxxxxxx PROC : db2sysc 0
INSTANCE: xxx NODE : 000 DB : xxx
APPHDL : 0-xxx APPID: *LOCAL.xxx.xxxxxxxxxxx
AUTHID : XXXX HOSTNAME: xxx
EDUID : 586 EDUNAME: db2agent (xxx) 0
FUNCTION: DB2 UDB, database utilities, sqluvtld_route_in, probe:924
DATA #1 : LOADID, PD_TYPE_LOADID, 48 bytes
LOADID: 586.2018-03-26-18.07.20.118756.0 (-1;-1)
DATA #2 : String, 53 bytes
Starting LOAD operation (S) (1) (I) [XXXXX .F2000].
2018-03-26-18.07.39.340596+480 I7052224E596 LEVEL: Warning
...
LOADID: 586.2018-03-26-18.07.20.118756.0 (65530;32774)
Starting LOAD phase at 03/26/2018 18:07:39.334619. Table XXXXX .F2000
2018-03-26-18.08.14.578323+480 I7053401E576 LEVEL: Warning
...
LOADID: 586.2018-03-26-18.07.20.118756.0 (65530;32774)
Completed LOAD phase at 03/26/2018 18:08:14.575917.
如果load已经结束,应该有如下条目:
2018-03-26-18.15.35.338325+480I7054525E600 LEVEL: Warning
...
LOADID: 586.2018-03-26-18.07.20.118756.0(65530;32774)
DATA #2 : String, 25 bytes
Completed LOAD operation.
综上,可以判定问题的原因是load作业在commit的时候用时过长,在正常的load阶段是持有的表级U锁,到了commit阶段时,load会加表级的Z锁,导致其他应用发生锁超时。
影响load commit时间有哪些因素呢,跟load的数据量有关系吗?于是查找IBM官方的支持文档,发现一个technote,如下
http://www-01.ibm.com/support/docview.wss?uid=swg21965042
从上面的technote可以看到,影响load commit时长的主要因素为:缓冲池越大、分区表中分区的数量越多,则commit时间越长。与load数据量本身关系不大。
IBM官方对此的解释如下:
Load在commit时需要purge 缓冲池,即将缓冲池中所有与这张表相关的页清除掉。这个操作需要扫描整个缓冲池,因此您会观察到缓冲池越大,commit时需要的时间越长。
另外,对于Range Partition表,在非pureScale环境中,所有partition是一起只做一遍purge 操作,即只扫描缓冲池一次(10.5的GA版就已经是这样的)。而在pureScale环境中,每个partition都需要单独做一次purge操作,即partition越多,扫描整个缓冲池的次数也变多了,load变慢比较显著。这个已经有客户开了RFE,但目前暂无改进计划。
非pureScale只扫描一次缓冲池,但对于缓冲池中的每个页则要遍历所有分区来判断它是否属于此Object的页,因此分区多仍然会带来开销,只是应该比多次扫描缓冲池开销小些。