Db2 ロック機構の内部構造を徹底解説:Lock Avoidance、Lock Escalation、Skip Locked まで

はじめに

この記事では、IBM Db2のロック機構の内部実装を深掘りします。

シリーズ最終回です。Db2はSQL Serverと同じくロックエスカレーションを持ちますが、Lock Avoidanceという独自の最適化で実際のロック取得を大幅に削減しています。Db2 11.5を中心に解説します。

Lock Avoidance

MVCCの記事でも触れましたが、Db2の最も特徴的なロック機能です。

仕組み

コミット済みであることが明らかな行に対して、ロックの取得自体をスキップします。

通常のロック:
  1. 行を読む
  2. ロックを取得
  3. 処理
  4. ロックを解放

Lock Avoidance:
  1. 行のログ情報を確認
  2. コミット済み? → YES → ロック不要、そのまま読む
                   → NO  → ロックを取得
-- Lock Avoidanceの効果を確認
db2 get snapshot for database on mydb | grep -i "lock avoidance"

Lock Avoidance                     = 98.5%

ほとんどの行はコミット済みなので、実際にロックが必要になるケースは少数です。

ロックの粒度

Db2もSQL Serverと同じく複数の粒度を持ちます:

粒度 説明
Table テーブル全体
Row

SQL ServerのようなPage粒度はありません。

ロックエスカレーション

Db2もSQL Serverと同じくロックエスカレーションがあります。

閾値

-- ロックエスカレーションの閾値
db2 get db cfg for mydb | grep -i lock

 Max storage for lock list (4KB)     (LOCKLIST) = 4096
 Percent of lock list before escalation (MAXLOCKS) = 22
  • LOCKLIST:ロックリスト全体のメモリサイズ
  • MAXLOCKS:1つの接続がLOCKLISTの何%を使ったらエスカレーション

SQL Serverとの違い

SQL Server Db2
閾値 約5,000行(固定的) LOCKLIST × MAXLOCKS%(設定可能)
無効化 テーブル単位で可能 LOCKSIZE TABLEで強制テーブルロック
パーティション単位 AUTO設定で可能 なし
-- テーブルのロック粒度を変更
ALTER TABLE employees LOCKSIZE ROW;    -- 行ロック(デフォルト)
ALTER TABLE employees LOCKSIZE TABLE;  -- テーブルロック(エスカレーション不要)

ロックモード

モード 略称 用途
Intent None IN 無条件読み取り(UR)
Intent Share IS 読み取り(CS/RS)
Share S 読み取りロック
Intent Exclusive IX 更新予定
Update U 更新ロック(デッドロック防止)
Exclusive X 書き込み

Uロック(Update Lock)はSQL Serverにもある概念で、「これから更新する予定の行」にかけます。S→Xへの昇格時のデッドロックを防ぎます。

SKIP LOCKED / DATA CAPTURE

SKIP LOCKED

Oracleと同様に、ロック中の行をスキップできます:

SELECT * FROM jobs WHERE status = 'pending'
FOR UPDATE WITH RS USE AND KEEP UPDATE LOCKS
SKIP LOCKED DATA
FETCH FIRST 1 ROW ONLY;

キュー処理パターンで有用です。

LOCK TIMEOUT

-- ロック待ちのタイムアウト(秒)
SET CURRENT LOCK TIMEOUT 10;

-- 即座にエラー(OracleのNOWAIT相当)
SET CURRENT LOCK TIMEOUT 0;

-- 無制限に待つ
SET CURRENT LOCK TIMEOUT -1;

デッドロック検出

Db2もデッドロックを自動検出します。

-- デッドロック検出の間隔
db2 get db cfg for mydb | grep DLCHKTIME
 Interval for checking deadlock (ms)  (DLCHKTIME) = 10000
InnoDB PostgreSQL Oracle SQL Server Db2
検出タイミング 即座 deadlock_timeout後 即座 即座 DLCHKTIME間隔
デッドロック時 Tx全体 Tx全体 ステートメントのみ Tx全体 Tx全体

まとめ:ロック管理シリーズ全体比較

トピック InnoDB PostgreSQL Oracle SQL Server Db2
読み取りのロック FOR SHARE時 FOR SHARE時 なし(CR Clone) デフォルトでSロック Lock Avoidanceで回避
行ロックの実装 ロックテーブル タプルヘッダ ITL(ブロック内) ロックマネージャ ロックリスト
ロックエスカレーション なし なし なし あり あり
Gap/Range Lock Next-Key Lock なし なし Key-Range Lock なし
SERIALIZABLE ロック SSI ロック ロック ロック
SKIP LOCKED 8.0〜 9.5〜 古くからあり あり あり
デッドロック時 Tx全体 Tx全体 ステートメントのみ Tx全体 Tx全体
独自機能 Insert Intention Lock Advisory Lock, SSI ITL, NOWAIT/WAIT NOLOCK, ロックヒント Lock Avoidance

5つのDBを比較すると、ロック設計は大きく2つの哲学に分かれます:

  • ロックを最小化する派(Oracle、Db2):読み取りはロックを取らない。CR CloneやLock Avoidanceで回避
  • ロックを活用する派(SQL Server):ロックで一貫性を保証。エスカレーションでメモリを管理
  • MVCCで代替する派(InnoDB、PostgreSQL):MVCCで読み書きの競合を回避。書き込み同士のみロック

参考文献

コメントする