TL

ロック粒度・意図ロックとロックエスカレーション

表を1個ロックすれば速いが並行性が死に、行ごとなら並行だがロック管理が重い――その板挟みを、意図ロックとエスカレーションがどう裁くかを原理から解きほぐします。

応用データベース同時実行制御ロックトランザクション最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.ロック粒度は粗いほど管理が軽く並行性が低い、細かいほど並行性が高く管理が重い、という相反のトレードオフ。階層ロックはこれを使い分ける枠組み。
  • 2.意図ロック(IS/IX/SIX)は上位ノードに「下位で S/X を取る予定」を宣言する札。これで行ロックと表ロックの衝突を、表を全走査せず O(1) で検出できる。
  • 3.ロック数が閾値を超えると、多数の行ロックを1個の表ロックへ置き換えるロックエスカレーションが起きる。メモリは救えるが並行性が落ち、デッドロックの新たな火種にもなる。

ロック粒度のトレードオフ

ロックをどの単位でかけるかを**ロック粒度(lock granularity)**と呼びます。データベースには表→ページ→行という包含階層があり(→ スロット式ページ構造)、ロックはこのどのレベルにもかけられます。粒度の選択は純粋なトレードオフです。

粒度並行性ロック管理コスト向く場面
表ロック(粗い)低い(1表に1人しか書けない)極小(ロックは1個)表全体を書き換えるバッチ・DDL
ページロック(中間)近接行をまとめて触る処理
行ロック(細かい)高い(別々の行は同時更新可)大(行数ぶんロックが増える)OLTP の単一行更新

粗い粒度は、ロック制御ブロックがメモリ上に1個で済むので管理が軽い反面、無関係な行まで巻き込んで並行性が下がります。細かい粒度はその逆で、1000行を更新すれば1000個のロックがロックマネージャのハッシュテーブルに乗り、メモリと CPU を食うかわりに行単位の並行更新ができます。万能な粒度はなく、トランザクションの性質ごとに最適点が動くため、現実の RDB は1つのトランザクション内で複数粒度を混在させます。これを成り立たせる仕組みが意図ロックです。

意図ロックが解く問題

複数粒度を混ぜると、ある厄介な問いが生じます。トランザクション T1 が表全体に X ロックを取りたいとき、別の T2 がその表のどこか1行に行ロックを持っていないかを知る必要があります。素朴に確かめるには表の全行を走査してロックの有無を調べねばならず、行数に比例したコストがかかって本末転倒です。

ここで使うのが意図ロック(intention lock)です。下位ノード(行)に実ロックを取る前に、その祖先ノード(ページ・表)に「この配下で S または X ロックを取るつもりだ」という予約の札を立てます。すると上位での衝突判定が、配下を一切走査せず表ノードのロック状態を見るだけで済みます。

意図ロックの取得規則

ロックは必ずルートから葉へ向かって取ります。行に S を取りたいなら、まず表に IS、(ページ層があれば)ページに IS、最後に行に S。行に X を取りたいなら、表とページに IX を立ててから行に X。逆順(葉から根)で取ると、上位の札が立つ前に下位ロックが成立してしまい、衝突判定の前提が崩れます。解放は逆に葉から根へ向かいます。

意図ロックの種類は3つです。**IS(intention shared)**は配下で S を取る予定、**IX(intention exclusive)**は配下で X を取る予定、**SIX(shared and intention exclusive)**はその表全体を S で読みつつ一部の行を X で更新する、という複合宣言です。SIX は「表全体を読む(S 相当)+一部行を書く(IX 相当)」を1つにまとめた最適化で、たとえば「全行をスキャンしながら条件に合う行だけ更新する」処理に対応します。

両立性行列(compatibility matrix)

どのロックが共存できるかは両立性行列で定義されます。同一ノードに既存ロックがある状態で新たなロックを要求したとき、両立すれば即時許可、両立しなければ待機(またはタイムアウト/デッドロック処理)になります。

要求 \ 既存ISIXSSIXX
IS×
IX×××
S×××
SIX××××
X×××××

この行列の読み解き方が肝心です。要点は3つです。

  • IS と IX は両立する:T1 が表のどこかの行を読む予定(IS)、T2 が別の行を書く予定(IX)でも、対象行が違えば衝突しないので、表ノードのレベルでは共存させてよい。実際の衝突は行ノードの S と X の両立性で改めて判定されます。意図ロック同士は「予定」の宣言にすぎないので、互いに緩いのです。
  • S と IX は両立しない:T1 が表全体を読む(S)一方で、T2 が表のどこかを書こうとする(IX)。T1 にとって「どこか書かれる」ことは読み取りの一貫性を壊すため、ここで弾く必要があります。これが意図ロックを上位に立てる最大の意義で、行を走査せずに表ノードだけで矛盾を検出できています。
  • SIX は IS としか両立しない:SIX 保持者は表全体を S で押さえているので、他者の書き込み予定(IX/SIX/X)も読み書き(S/X)も拒み、許せるのは「読む予定」の IS だけです。
意図ロックは“実ロック”ではない

IS/IX は配下のロックと衝突しないための上位の予約であって、それ自体がデータの読み書き権限を与えるわけではありません。実際に行を読む/書く権利は、葉ノードに取った S/X が与えます。試験では「IX を取れば行を更新できる」式のひっかけが頻出ですが、IX は『下で X を取りますよ』という宣言にすぎず、更新権は行の X そのものです。

ロックエスカレーション

行ロックは並行性に優れますが、1トランザクションが大量の行を触るとロック制御ブロックがメモリを圧迫します。SQL Server では1ロックが約 100 バイト前後、これが数十万個積もればロックマネージャだけで無視できない量になります。そこで多くの RDB は、多数の細粒度ロックを少数の粗粒度ロックへ自動的に置き換える機構を持ちます。これがロックエスカレーションです。

判定のトリガは実装ごとに異なります。SQL Server は「単一インデックス/表で取得した行・ページロックが概ね 5000 個を超える」または「ロック用メモリが上限に達した」とき、行/ページロックを表ロックへ昇格させます(中間のページ単位ではなく一気に表へ飛ぶのが特徴)。多くの実装でエスカレーションは行→ページ→表ではなく、行/ページ→表へ直行します。

昇格の方向とロック種別

エスカレーション後のロック種別は元の意図を引き継ぎます。配下に X(書き込み)を含んでいた、つまり表に IX/SIX を保持していたなら表 X ロックへ、読み取りだけ(表に IS)なら表 S ロックへ昇格します。昇格は『下位ロックをまとめて1つの上位ロックに畳む』操作なので、いったん表 X が成立すれば配下の個別行ロックは不要になり解放されます。

エスカレーションの代償

表ロックへ昇格した瞬間、その表に対する他トランザクションの並行アクセスはほぼ止まります。読み取りバッチが表 S を取れば他者の書き込みが、更新バッチが表 X を取ればあらゆる他者がブロックされます。メモリ節約と引き換えに並行性を大きく失うのがエスカレーションの本質的なコストで、OLTP で長時間の大量更新を流すと、この昇格が原因で広範囲のブロッキングを招きます。

さらにエスカレーションはデッドロックの新たな火種になります。複数トランザクションが同時に同じ表で昇格を試みると、互いの行ロック解放を待ち合って膠着しうるためです(→ デッドロック検出)。回避の定石は次の通りです。

  • トランザクションを小さく分割する。1回の更新行数を閾値(例: SQL Server なら 5000)より十分小さく保てば昇格は起きません。大量更新はバッチに区切るのが基本対策です。
  • エスカレーションを抑止/制御する。SQL Server なら ALTER TABLE ... SET (LOCK_ESCALATION = DISABLE) で表単位に無効化でき、パーティション単位への昇格(AUTO)も選べます。
  • 粗い粒度を意図的に先取りする。最初から表ロックを取ると割り切れる長大バッチでは、明示的に表ロックを取ってしまえば昇格による途中の挙動変化やデッドロックを避けられます。
-- SQL Server: 大量更新を 1000 行ずつに区切り、昇格(>=5000)を回避する例
WHILE 1 = 1
BEGIN
  UPDATE TOP (1000) dbo.orders
    SET status = 'archived'
    WHERE status = 'closed' AND archived = 0;
  IF @@ROWCOUNT = 0 BREAK;   -- 触った行が 0 になったら終了
  -- 各バッチを個別トランザクションにすればロックは都度解放される
END

まとめ

  • ロック粒度は「粗い=管理軽・並行性低/細かい=管理重・並行性高」の相反トレードオフ。階層ロックは1トランザクション内で粒度を混在させてこれを両立する。
  • **意図ロック(IS/IX/SIX)**は上位ノードに下位ロックの予約を立て、配下を走査せず O(1) で衝突を判定するための仕組み。実ロックは葉の S/X が担い、IS/IX は予約にすぎない。
  • 両立性行列の核心は「IS と IX は両立、S と IX は非両立」。これにより表全体の読みと一部行の書きの矛盾を上位ノードだけで検出できる。
  • ロックエスカレーションは大量の行ロックを表ロックへ畳んでメモリを救うが、並行性を犠牲にしデッドロックの火種にもなる。対策はトランザクション分割・昇格制御・粗粒度の先取り。隔離レベルとの兼ね合いは トランザクション分離レベル と合わせて押さえる。

データベース Article

ロック粒度・意図ロックとロックエスカレーションを実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

データベース

比較で見る軸

難易度: advanced / カテゴリ: データベース / タグ数: 4

導入後に効く点

意図ロック(IS/IX/SIX)は上位ノードに「下位で S/X を取る予定」を宣言する札。これで行ロックと表ロックの衝突を、表を全走査せず O(1) で検出できる。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
データベース
タグ数
4

判断チェックリスト

  • 自社の用途が「データベース / 同時実行制御」に近いか確認する。
  • 強みである「ロック粒度は粗いほど管理が軽く並行性が低い、細かいほど並行性が高く管理が重い、という相反のトレードオフ。階層ロックはこれを使い分ける枠組み。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

データベース同時実行制御ロックトランザクションデータベース同時実行制御ロックトランザクション
参考: 公式情報