ロックの基本 — SQL Server はこう動く
ロック = トランザクションの ACID を守る
仕組み
書き込み = X (排他) ロック、読み取り = S
(共有) ロック → X と S は両立しない
SQL Server の既定 (READ COMMITTED)
は「ロックベース」
更新中の行は読み取りもブロックされる
PostgreSQL / Oracle / MySQL (InnoDB) の
MVCC (Multi-Version Concurrency Control)
とはここが違う
U (更新: Update) = 更新候補を調べるとき
に取る SQL Server 特有のロック
Slide 5
Slide 5 text
課題① ロックメモリ
1,000 行 UPDATE = 1,000 個の X 行
ロックをトランザクション終了まで保持
大量更新ではロックメモリが膨らむ
テーブル (1,000 行を UPDATE)
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
… X 行ロック ×1,000 (コミットまで保持)
ロック 1 個ごとにメモリを消費
ロックメモリが膨らむ
Slide 6
Slide 6 text
課題② ロックエスカレーション
行ロックが増える (目安 5,000 個超) と
テーブルロックに昇格
ロックをメモリで管理する SQL Server
固有の節約機構、だが…
行ロック ×5,000 超
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
昇格
テーブルロック ×1
→ 無関係な行までブロック / 同時実行性が
低下
Slide 7
Slide 7 text
課題③ U ロックによるブロッキング
スキャン中、条件判定のために各行へ U
ロックを取得
条件に合わない行を通過するだけでもブ
ロックされる
※適切なインデックスがあればこの例は回
避可能 — ただし万能ではない
セッション2: UPDATE … WHERE a=2 (スキャン)
行1 の U ロック取得で停止 → ブロック!
行1
X 保持中
(セッション1)
行2
(a=2)
行3
行4
コンポーネント① TID ロック
各行は最後に変更したトランザクション
の TID を持つ
行・ページロックは更新した瞬間に解放
→ 保持は XACT への X ロック 1 個だけ
従来
X
最適化されたロック
X
X
X
X
X
X
行・ページロックは更新した瞬間に解放
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XACT に X ロック ×1
保持: X 行ロック ×1,000
保持はこの 1 個だけ
Slide 10
Slide 10 text
コンポーネント② LAQ (修飾後ロック)
U ロックを取らず、最新コミット済みバー
ジョンで述語を評価
条件を満たした行だけ X ロックを取得
前提: RCSI (Read Committed Snapshot
Isolation)
セッション2: UPDATE … WHERE a=2 (スキャン)
ブロックされない!
行1 は素通り (コミット済みバージョンで判定)
行1
X 保持中
(セッション1)
行2
(a=2)
X 取得して更新
行3
行4