SQL Serverを利用していると、複数の処理が同時にデータを更新した際にデッドロックが発生することがあります。デッドロックが起きると処理が停止したように見えるため、「SQL Serverは自動的にどちらか一方を終了させるのか」と疑問に感じることがあります。この記事では、SQL Serverのデッドロック発生時の動作や、どの処理が終了対象になるのか、そしてデッドロックを防ぐための基本的な対策について解説します。
SQL Serverではデッドロック発生時に自動で被害者を選択する
SQL Serverでは、デッドロックが発生するとデータベースエンジンが自動的に状況を検出し、複数の処理のうち1つを「デッドロックの被害者」として選択して終了させます。
つまり、処理同士が互いにロックを保持して待機し続ける状態になった場合、SQL Serverが片方のトランザクションを強制的にロールバックすることで、デッドロック状態を解消します。
そのため、SQL Serverではデッドロックによってシステム全体が永久に停止することはありません。ただし、終了された処理側ではエラーが発生するため、アプリケーション側で適切に処理する必要があります。
デッドロックが発生する仕組み
デッドロックは、複数のトランザクションがお互いに必要なロックを待っている状態で発生します。
例えば、以下のような状況を考えます。
| 処理 | 取得しているロック | 待機している対象 |
|---|---|---|
| 処理A | テーブルA | テーブルB |
| 処理B | テーブルB | テーブルA |
処理AはテーブルAをロックしたままテーブルBの解放を待ち、処理BはテーブルBをロックしたままテーブルAの解放を待ちます。この状態になると、どちらも先に進めなくなります。
SQL Serverはこの循環状態を検出すると、どちらか一方を終了させてロックを解放します。
どの処理がデッドロックの被害者になるのか
SQL Serverは単純に先に開始した処理や後から開始した処理を終了させるわけではありません。デッドロックの被害者は、主に「ロールバックにかかるコスト」を基準に選択されます。
また、SET DEADLOCK_PRIORITYを利用すると、処理ごとに被害者になりやすさを設定できます。
SET DEADLOCK_PRIORITY LOW;
例えば、重要度の低いバックグラウンド処理の優先度を低く設定しておけば、ユーザー操作に関わる処理を優先的に継続させる設計が可能です。
逆に、どの処理も同じ優先度の場合は、SQL Serverが内部的な判断で被害者を決定します。
デッドロック発生時にアプリケーションで必要な対応
デッドロックの被害者になったトランザクションは、自動的にロールバックされ、エラー番号1205が返されます。
そのため、アプリケーション側ではデッドロックエラーを検知し、必要に応じて処理を再実行する仕組みを用意することが一般的です。
トランザクション (プロセス ID xx) が、lock リソースで他のプロセスとデッドロックしました。
例えば、ネット通販の注文処理で一時的にデッドロックが発生した場合、ユーザーにエラーを表示するだけではなく、数秒後に自動リトライする仕組みにすると利用者への影響を減らせます。
SQL Serverのデッドロックを防ぐ基本的な対策
デッドロックはSQL Serverの標準機能によって解消されますが、頻繁に発生する場合は設計を見直す必要があります。
代表的な対策には以下があります。
- 複数テーブルを更新する順番を統一する
- トランザクションの範囲を必要以上に広げない
- 長時間の処理中にロックを保持し続けない
- 適切なインデックスを設定して処理時間を短縮する
例えば、処理Aでは「顧客テーブル→注文テーブル」の順番で更新し、処理Bでは「注文テーブル→顧客テーブル」の順番で更新している場合、ロック待ちが発生しやすくなります。
すべての処理で同じ順番でテーブルへアクセスするように設計すると、デッドロック発生率を下げることができます。
デッドロックの調査方法
デッドロックが発生した場合は、原因となったSQLやロック状況を確認することが重要です。
SQL Serverでは拡張イベントやSQL Server Profilerなどを利用して、どの処理同士が競合したのかを確認できます。
原因を特定すると、「不要なロックを発生させていた」「インデックス不足で処理時間が長くなっていた」といった問題が見つかる場合があります。
まとめ|SQL Serverはデッドロック時に自動で一方の処理を終了する
SQL Serverでは、デッドロックが発生すると自動的に状況を検出し、一方のトランザクションを被害者として終了させます。
終了された処理はロールバックされ、エラー1205が発生します。そのため、アプリケーション側では再試行処理などを考慮することが重要です。
ただし、頻繁なデッドロックはシステム設計やSQLの問題が原因であることが多いため、テーブルアクセス順序の統一やトランザクション時間の短縮、インデックス改善などによって根本的な対策を行うことが大切です。

コメント