QuestのDatabaseTrainingDays Fall Seriesの一環として、Microsoft CertifiedMasterのBrentOzarが、「クエリチューニングによるデッドロックの回避」に関するチュートリアルを発表しました。このプログラムは、SQL Serverで発生する3つの同時実行性の問題、それらを修正する3つの方法、およびそれらを修正するように見える1つの方法に焦点を当てましたが、実際にはそうではありません。
同時実行の問題:SQL Serverでのロック、ブロック、デッドロック
並行性の問題とは何ですか?これらは、クエリがテーブルなどのデータベースオブジェクトを介して相互に競合しないようにしようとしたときに発生します。それらは:
- ロック –クエリは常にこれを実行して、他のクエリが同時にテーブルを使用するのを防ぎます。これは通常のデータベース操作です。
- ブロック –これは、1つのクエリに通常のロックがあるが、別のクエリが同じロックを取得しようとした場合に発生します。 2番目のクエリは、最初のクエリがロックを解放するまで必要なだけ待機する必要があります。最初のクエリの性質に応じて、2番目のクエリは非常に短い時間または非常に長い時間待機する可能性があります。パフォーマンスに実際に影響を与えるのは、これらの長い待機時間です。
- デッドロック –デッドロックは、1つのクエリがロックを取得し、別のクエリが別のロックを取得し、それぞれが他方のロックを取得しようとしたときに発生します。 SQL Serverは、クエリの1つを犠牲者として指定し、それを強制終了してスタンドオフを解除することにより、これを解決します。クエリの1つを続行できますが、これはパフォーマンスにも影響します。
同時実行の問題の修正
SQL Serverでブロックまたはデッドロックが発生しているかどうかに関係なく、同時実行性の問題を修正する方法があります。ブレントはこれらの3つの方法を提示し、セッションの残りのほとんどを2番目の方法(不正なコードの修正)に集中して費やしました。
- クエリを高速化するのに十分なインデックスを用意しますが、クエリがより多くのロックを長時間保持するようにすることで処理が遅くなるほど多くはありません。
- トランザクションコードを調整して、クエリが毎回同じ予測可能な順序でテーブルを処理するようにします
- アプリケーションのニーズに適した分離レベルを使用する
プログラムの実践的な部分に飛び込んだとき、ブレントはブロックとデッドロックにNOLOCKステートメントを使用することについてコメントしました。彼は、NOLOCKは「ダーティリード」に依存しているため、これらの問題を実際には修正しないと警告しました。基本的に、他のクエリの行ロックを無視します。
Stack Overflowデータベースを使用したこれのデモンストレーションで、彼は「Alex」という名前の人を探して数える簡単なクエリを作成しました。次に、そうでない人に対して更新を実行する別のクエリを作成しました Alexという名前-レコードの挿入または削除はありません。 1つのクエリは他のクエリとは何の関係もありません。しかし、それらを一緒に実行すると、Alexという名前の人の数に異なる結果が生じます。これは、NOLOCKを使用すると、コミットされていないデータを表示できるため、予測できないランダムな結果が生じるためです。並行性の下でのみ発生します。
明らかに、SQL Serverでのブロックとデッドロックには、ランダムで予測できない結果をもたらさない、より優れた修正が必要です。
SQLデッドロックのより良いソリューション
次に、ブレントは、デッドロックの原因となるコードを変更することにより、デッドロックを修正する方法を示しました。彼の最初のデモは、2つのテーブルを含む単純な状況を示したため、聴衆は、それが起こっている間、スローモーションでデッドロックを見ることができました。 SQL Serverは5秒ごとにデッドロックを検索し、ロールバックするのが最も簡単なクエリを強制終了するため、デッドロックの犠牲者が出現するのを確認できました。
単純な状況では、最も一般的なアドバイスが適用されます。それは、クエリを作成するたびに同じ順序でテーブルにアクセスすることです。これにより、通常、クエリが互いにデッドロックするのを防ぐことができます。
より複雑なクエリはどうですか?このシナリオでは、Brentは、2人がお互いの質問に賛成しているStackOverflowで簡単に発生する可能性のあるより現実的な状況を使用しました。同じユーザーが両方のトランザクションに関与しているため、これによりデッドロックが発生します。
ここでは、毎回同じ順序で各テーブルを処理するだけでは不十分ですが、各テーブルがタッチされる回数を最小限に抑える必要もあります。ブレントが説明したように、修正には、クエリをブロックさせる醜いコードが含まれる可能性がありますが、少なくともデッドロックは発生しません。この場合、両方のクエリを完了まで実行できる短い期間のブロックは、一方を終了するデッドロックよりも優れています。
何百ものクエリでコードを変更したくないので、常にデッドロックしているコードに焦点を合わせ、トランザクションから不要な行を削除し、デッドロックを回避するためにブロックを導入することを恐れないでください。