DB2 for z/OSには従来からロックエスカレーションを抑止する機能が提供されていたのですが、FIXPACKによる機能追加でDB2 for LUW 11.1.2.2以降でも同様のことが出来るようになりました。
ロックエスカレーションとは
ロックエスカレーションとは、大量の行ロックを表ロックにまとめることで、ロックの情報を保持するメモリの使用量やロック獲得・解放のオーバーヘッドを削減する機能です。
表を排他的に利用するバッチ処理では処理時間の短縮に有効なケースがありますが、ロック競合が多発し大事故を起こすこともあるため活用するのが難しい機能でもあります。そのため、RDBMSによってはロックエスカレーションの機能は提供されていません(むしろある方が少数派か)。
- ロックエスカレーションあり
- DB2
- SQL Server
- ロックエスカレーションなし
- Oracle
- My SQL
- PostgreSQL
DB2ではロックの情報を保持するメモリ領域であるロックリストが一杯になった場合、もしくはDB構成パラメータMAXLOCKS
で指定した割合を超えた場合にロックエスカレーションが発生します。
なお、DB2 9.1以降ではロックリストはセルフチューニングメモリ機能の管理対象となっており、DB構成パラメータLOCKLIST
がAUTOMATIC
の場合は不足時に自動的にサイズ拡張され、従来よりロックエスカレーションが発生しにくくなっています。
設定方法
新たに用意されたレジストリ変数DB2_AVOID_LOCK_ESCALATION
をON
にすることで、ロックリストが一杯になった場合はSQL0912Nでエラーが返されるようになります。
$ db2set DB2_AVOID_LOCK_ESCALATION=ON -i
検証してみた
環境
- Db2 11.1.3.3 Express-C Edition
- VirtualBox 5.2.3
- Vagrant 2.0.3
- Ubuntu Linux 16.04.4 64-bit (ubuntu/xenial64)
検証手順・結果
ロックリストの縮小
ロックエスカレーションが発生しやすいよう、ロックリストを最小サイズにしておきます。値の単位は4KBです。
db2inst1@ubuntu-xenial:~$ db2 update db cfg using locklist 4
DB20000I The UPDATE DATABASE CONFIGURATION command completed successfully.
db2inst1@ubuntu-xenial:~$ db2 "get db cfg" | grep -i locklist
Max storage for lock list (4KB) (LOCKLIST) = 4
SQLの実行(ロックエスカレーション発生ケース)
分離レベルRSで表をスキャンすることで、全レコードのSロックを獲得させてみます。
db2 => select count(*) from sysibm.systables with rs
1
-----------
646
1 record(s) selected.
SQLの実行は成功していますが、その裏ではロックエスカレーションが発生していました。
db2inst1@ubuntu-xenial:~$ db2diag -g MESSAGE^=ADM550
2018-04-21-07.57.17.685278+000 E98572E1013 LEVEL: Info
PID : 611 TID : 140657632995072 PROC : db2sysc
INSTANCE: db2inst1 NODE : 000 DB : TESTDB01
APPHDL : 0-232 APPID: *LOCAL.db2inst1.180421075455
AUTHID : DB2INST1 HOSTNAME: ubuntu-xenial
EDUID : 40 EDUNAME: db2agent (TESTDB01)
FUNCTION: DB2 UDB, data management, sqldEscalateLocks, probe:1
MESSAGE : ADM5501I The database manager is performing lock escalation. The
affected application is named "db2bp", and is associated with the
workload name "SYSDEFAULTUSERWORKLOAD" and application ID
"*LOCAL.db2inst1.180421075455" at member "0". The total number of
locks currently held is "291", and the target number of locks to hold
is "145". The current statement being executed is "select count(*)
from sysibm.systables with rs". Reason code: "2"
DATA #1 : Hex integer, 8 bytes
0x830000000004003B
2018-04-21-07.57.17.701216+000 E100154E576 LEVEL: Warning
PID : 611 TID : 140657632995072 PROC : db2sysc
INSTANCE: db2inst1 NODE : 000 DB : TESTDB01
APPHDL : 0-232 APPID: *LOCAL.db2inst1.180421075455
AUTHID : DB2INST1 HOSTNAME: ubuntu-xenial
EDUID : 40 EDUNAME: db2agent (TESTDB01)
FUNCTION: DB2 UDB, data management, sqldEscalateLocks, probe:3
MESSAGE : ADM5502W The escalation of "241" locks on table "SYSIBM .SYSTABLES"
to lock intent "S" was successful.
DB2_AVOID_LOCK_ESCALATIONの変更
db2setコマンドでレジストリ変数を変更します。
db2inst1@ubuntu-xenial:~$ db2set -all
[i] DB2COMM=TCPIP
[i] DB2AUTOSTART=NO
[g] DB2_COMPATIBILITY_VECTOR=MYS
[g] DB2SYSTEM=ubuntu-xenial
db2inst1@ubuntu-xenial:~$ db2set DB2_AVOID_LOCK_ESCALATION=ON -i
db2inst1@ubuntu-xenial:~$ db2set -all
[i] DB2_AVOID_LOCK_ESCALATION=ON
[i] DB2COMM=TCPIP
[i] DB2AUTOSTART=NO
[g] DB2_COMPATIBILITY_VECTOR=MYS
[g] DB2SYSTEM=ubuntu-xenial
SQLの実行(SQL0912Nケース)
ロックエスカレーションを発生させずにSQLを止めることが出来ました。
db2 => select count(*) from sysibm.systables with rs
1
-----------
SQL0912N The maximum number of lock requests has been reached for the
database. Reason code = "1" SQLSTATE=57011
参考資料
- IBM Knowledge Center