web-dev-qa-db-ja.com

「データの移動が原因でNOLOCKでスキャンを続行できませんでした」を再現する方法

選択クエリにWITH (NOLOCK)がある一部の大きなジョブで、「データの移動のため、NOLOCKでスキャンを続行できませんでした」というメッセージがときどき表示されます。

これは、ページ分割があり、データが本来あるべき場所でなくなったときにデータを選択しようとすることと関係があることを理解しています。それが私の環境で起こっていることだと思います。

これをどのように再現しますか?

短期的な回避策を実行してエラーをキャッチし、これが発生したときに再試行しようとしていますが、再現できない場合はテストできません。これを引き起こす合理的に信頼できる方法はありますか?

それが発生した場合、クエリを再度実行すると成功します。そのため、実際のデータやデータベースが永続的に破損する心配はありません。クエリ内の一部のテーブル(およびインデックス)は、頻繁に削除、再作成、再設定されるため、これに関連していると想定しています。

NOLOCKの削除は、私が対処する長期的な問題です。 NOLOCKが最初に配置された理由は、クエリが非常に悪いため、日常のトランザクションでデッドロックが発生していたため、NOLOCKはデッドロックを阻止するためのバンドエイドでした(うまくいった)。永久的な解決策ができるまで、私はバンドエイドの上にバンドエイドを必要とします。

Hello Worldでそれを再現できれば、おそらく1時間もかからずにバンドエイドを仕事に投入することを計画しています。検索と置換NOLOCKを削除できません。これは、アプリのデッドロックが再び発生し始めるため、時々失敗するジョブよりも悪いことです。

コミットされた読み取りスナップショット分離を使用することは十分な可能性です。詳細については、データベースチームと協力する必要があります。私たちの問題の一部は、そのようなことを処理するSQL Serverの専門家がいないことです。私は、現時点でその変更を行うのに十分な分離レベルを理解していません。

10
wookie23

NOLOCKの問題に対する潜在的な「バンドエイド」の1つは、NOLOCKの使用を停止してREAD_COMMITTED_SNAPSHOT分離の使用を開始することなので、ケンドラによる http://www.brentozar.com のブログ投稿を紹介します。少し: SQL Serverでのスナップショットまたは読み取りコミットスナップショット分離の実装:ガイド

ケンドラは、READ_COMMITTED_SNAPSHOT分離レベルを使用した場合の利点とリスクに関するかなりの詳細を提供しています。

  1. この分離レベルは、データベースコードのデフォルトの分離レベルになります。
  2. READ_COMMITTED_SNAPSHOT分離レベルを変更するには、データベースに1人のユーザーのみが必要です。
  3. READ_COMMITTED_SNAPSHOT分離を使用する場合でも、NOLOCKヒントはデフォルトをオーバーライドするため、削除する必要があります。
  4. 一部のコードには、修復が必要な問題がある可能性があります。

数年前、データベースにREAD_COMMITTED_SNAPSHOT分離を実装しましたが、重大なブロッキングの影響を受けていました-)。しかし、分離レベルを変更すると、いくつかの重要な領域でデッドロックが発生し始めました。

なぜこれが起こったのですか?以前の分離レベルでは大量のブロックが発生したため、コードはデッドロックのポイントに「到達」できませんでした。ただし、READ_COMMITTED_SNAPSHOT分離を使用すると、クエリが前進し続ける可能性があります。ただし、待機していないトランザクションの一部はデッドロックを始めました。

幸いなことに、デッドロックポイントを特定し、いくつかのテーブルのインデックスを調整してより合理的な列順序にすることで、ケースは迅速に解決されました。これにより、ロックの問題が大幅に軽減されました。

8
RLF