データベーススペシャリスト 2016年 午前2 問13
問題文
DBMSにおいて、トランザクション間でデッドロックが発生していることを検出するために使用するものはどれか。
選択肢
ア:2相ロック
イ:時刻印アルゴリズム
ウ:チェックポイント
エ:待ちグラフ(正解)
🔒 解説は解答すると表示されます
待ちグラフ【午前2解説】
正解の理由
トランザクション間の「誰が誰を待っているか」を表現して、サイクルの存在でデッドロックを検出するのが待ちグラフです。そのためデッドロックの検出手段として最も直接的かつ標準的なのは エ の待ちグラフです。待ちグラフは各トランザクションをノードとし、トランザクション Ti がロックを待っていてそのロックを Tj が保持しているときに有向辺 Ti → Tj を張ります。このグラフにサイクルが存在すれば互いに待ち合う状態、すなわちデッドロックが発生しています。サイクル検出は深さ優先探索(DFS)やTarjanの強連結成分検出などで効率よく行えます(計算量は 程度)。
解法ステップ
- 問題が「デッドロックの検出」を求めていることを確認する。
- 各選択肢の目的を素早く整理する:ロック方式(2相ロック)、時刻方式(タイムスタンプ)、チェックポイント(リカバリ用)、待ちグラフ(待機関係を表現)。
- 「検出」に直結するのは「待機関係を可視化しサイクルを確認する手法」であると判断する。
- よって待ちグラフ(エ)を選ぶ。
選択肢別の誤答解説
- ア: 2相ロック(2PL)
2相ロックはロックの「成長相」と「収縮相」によって直列化(serializability)を保証するロックプロトコルです。重要点として、2相ロックはデッドロックを必ず防ぐものではなく、むしろデッドロックを発生させうる方式です(複数トランザクションが互いのロックを待つとデッドロックが発生する)。したがって、デッドロックの「検出」手段ではありません。検出は待ちグラフやタイムアウト等で行い、予防・回避には資源順序化やwait‑die/wound‑wait等の手法を使います。 - イ: 時刻印アルゴリズム(タイムスタンプ)
タイムスタンプ方式はトランザクションに時刻(タイムスタンプ)を割り当てて競合を解決する方式で、待たせる代わりにロールバックを行うことが多く、基本的にはブロッキングを回避するためデッドロックは生じにくい(事実上デッドロック検出を必要としない)設計です。よって「検出」に使うものではありません。 - ウ: チェックポイント
チェックポイントはデータベースの復旧(クラッシュ後のリカバリ)を高速化するための手法であり、トランザクションのデッドロック検出とは目的が異なります。 - エ: 待ちグラフ(正解)
トランザクションの待ち関係をグラフで表し、グラフ上のサイクル検出によりデッドロックを検出します。分散環境では分割された待ちグラフの統合など実装上の工夫が必要ですが、基本概念は同じです。
よくある誤解
- 2相ロックはデッドロックを防ぐ/検出する方法である:誤りです。2相ロックは直列化を保証しますが、デッドロックを発生させ得ます。検出は別の仕組み(待ちグラフやタイムアウト)で行います。
- タイムスタンプ方式もデッドロック検出に使う:一般的にタイムスタンプ方式は待機を伴わない選択をするため、デッドロック検出を必要としないことが多い点が誤解されやすいです。
- 待ちグラフにサイクルが無ければ問題ない:通常は正しいですが、分散システムでは部分的にしか見えないグラフからは検出できないケースがあるため、グローバル検出の工夫が必要です。
補足コラム
- 待ちグラフの作り方:ノード=トランザクション、辺=「ロック待ちの依存関係(待っている→保持者)」です。周期があればデッドロック。
- 検出アルゴリズム例:単一ノードではDFSで十分、複数ノード/分散環境では部分グラフを収集して統合しサイクル検出を行うか、タイムアウトや分散検出アルゴリズムを用います。
- 解決方法:デッドロックを検出したら、いずれかのトランザクションを中止(ロールバック)してサイクルを破壊します。被害を小さくするための犠牲者選択基準としては「実行時間が短い/持っているロック数が少ない/再実行コストが小さい」などがあります。
- 防止手法の例:
- 資源順序化(すべてのトランザクションが同じ固定順序で資源を要求する)
- タイムアウト(一定時間待ったトランザクションを中止)
- wait‑die / wound‑wait(タイムスタンプに基づく回避ルール)
- 参考計算量:グラフのサイクル検出は (頂点数 V、辺数 E)。
簡単な実装例(待ちグラフでサイクル検出するDFS、Python):
# graph: adjacency list, e.g. {'T1':['T2'], 'T2':['T3'], 'T3':['T1']}
def has_cycle(graph):
visited = set()
stack = set()
def dfs(u):
visited.add(u); stack.add(u)
for v in graph.get(u, []):
if v not in visited:
if dfs(v): return True
elif v in stack:
return True
stack.remove(u)
return False
for node in graph:
if node not in visited:
if dfs(node): return True
return False
FAQ
Q1: 2相ロックでデッドロックが起きた場合、自動で検出されますか?
A1: いいえ。2相ロック自体は検出機構を持ちません。多くのDBMSは待ちグラフやタイムアウトで別途検出し、検出後にトランザクションを中止して解消します。
A1: いいえ。2相ロック自体は検出機構を持ちません。多くのDBMSは待ちグラフやタイムアウトで別途検出し、検出後にトランザクションを中止して解消します。
Q2: タイムスタンプ方式はデッドロック対策になりますか?
A2: 基本的にタイムスタンプ方式はブロッキングを減らすため、デッドロックを発生させにくい仕組みです。そのため通常はデッドロック検出を必要としません。
A2: 基本的にタイムスタンプ方式はブロッキングを減らすため、デッドロックを発生させにくい仕組みです。そのため通常はデッドロック検出を必要としません。
Q3: 分散トランザクションでは待ちグラフだけで十分ですか?
A3: 部分的な視点しか持てないと検出できない場合があるため、グローバルに統合する仕組みやタイムアウト、分散検出アルゴリズムが必要になります。
A3: 部分的な視点しか持てないと検出できない場合があるため、グローバルに統合する仕組みやタイムアウト、分散検出アルゴリズムが必要になります。
関連キーワード: 待ちグラフ、デッドロック検出、サイクル検出、2相ロック、タイムスタンプ方式、チェックポイント、トランザクション制御、wait‑die、wound‑wait

\ せっかくなら /
データベーススペシャリストを
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

