動的SQLを使用して次のクエリを実行しています。同時インスタンスを実行すると、いくつかのケースでエラーが発生します。エラーは:
データ移動のため、NOLOCKでスキャンを続行できませんでした...
この質問 は、あるプロセスが別のプロセスによって削除されているデータを読み取ったときにこのエラーがスローされると述べています。私たちのプロセスは同じ行を削除して読み取りますが、次のクエリのように、次々と続きます(SELECT
はDELETE
の後にあります)
DELETE FROM Table1
WHERE colum1 = somevalue1
AND column2 = somevalue2
SELECT COUNT(*)
FROM Table1 WITH (NOLOCK)
WHERE colum1 = somevalue1
AND column2 = somevalue2
上記のクエリの実行を理解しようとしています。 SELECT
はコミットされていないので、DELETE
がコミットされる前に実行されますか?これは、NOLOCK
ヒントを削除するとエラーが停止することを意味しますか?
SELECT
はコミットされていないので、DELETE
がコミットされる前に実行を開始しますか?
いいえ、T-SQLステートメントは常にSQL Serverで順次実行されます。重要なのは、SELECT
が読み取り可能コミットされていない変更同時に実行されている他のトランザクションによって行われたものです。
これは
NOLOCK
を削除するとエラーが停止することを意味しますか?
はい、ただし エラー601 は トランザクション分離レベル がREAD UNCOMMITTED
の場合にのみ可能です。別の分離レベルに移動すると、その特定のエラーは発生しなくなります。
エラー601はさまざまな理由で発生する可能性がありますが、すべてが共通のテーマを共有しています。SQLServerエンジンは、存在するはずの構造が別のオブジェクトによって移動または削除された状況に遭遇したときに、いくつかのポインターチェーンなどに従っていました同時実行プロセス。
エラー601が発生する可能性のあるケースの数は、SQL Serverのリリース全体で段階的に削減されており、SQL Server 2012はこのエラーを返す可能性が最も低くなっていますが、それでも可能です。
私の見解では、エラー601のインシデントはすべてバグであり、適切な値は「バグ」です。この動作は確かに望ましくなく、SQL標準のREAD UNCOMMITTED
分離レベルで発生する可能性のある現象の説明をはるかに超えています。
SQL標準がさまざまな分離レベルの詳細な動作を定義していないことは確かに事実です 非常によく 、それが言うことは結果のみの一般的な信念につながりますREAD UNCOMMITTED
の意味は、トランザクションは、他のトランザクションがコミットする前に、別のトランザクションによって変更されたデータを見る可能性があるということです。その結果、READ UNCOMMITTED
分離レベルを使用することは、ほとんどすべてのトランザクションが非常に速くコミットする(そしてロールバックが非常に少ない)ため、多くの場合正当化されます。
残念ながら、SQL ServerでのREAD UNCOMMITTED
の実装ははるかに単純なダーティリードよりも進んでいます。 SQL ServerのREAD UNCOMMITTED
トランザクションは、重複データ、大きなデータ型の部分的な読み取り、データレコード全体のスキップを返すか、単に601エラーで失敗する可能性があります。
READ COMMITTED
でこれらの動作のいくつかを体験するのは 可能 です および偶数REPEATABLE READ
。これにより、受け入れ可能な分離レベルは、少なくともステートメントレベルの一貫性を提供するもの、つまりrow-versioning READ COMMITTED
、SNAPSHOT
分離、またはSERIALIZABLE
のみであると結論付ける人もいます。
これらのうち、通常、row-versioning READ COMMITTED
が最も簡単に移行できます。行バージョンの分離レベルの詳細については、 このBooks Onlineトピック とそのサブツリーを参照してください。