web-dev-qa-db-ja.com

順次削除とコミットされていない読み取りの実行

動的SQLを使用して次のクエリを実行しています。同時インスタンスを実行すると、いくつかのケースでエラーが発生します。エラーは:

データ移動のため、NOLOCKでスキャンを続行できませんでした...

この質問 は、あるプロセスが別のプロセスによって削除されているデータを読み取ったときにこのエラーがスローされると述べています。私たちのプロセスは同じ行を削除して読み取りますが、次のクエリのように、次々と続きます(SELECTDELETEの後にあります)

DELETE FROM Table1
WHERE colum1 = somevalue1
AND column2 = somevalue2

SELECT COUNT(*) 
FROM Table1 WITH (NOLOCK)
WHERE colum1 = somevalue1
AND column2 = somevalue2

上記のクエリの実行を理解しようとしています。 SELECTはコミットされていないので、DELETEがコミットされる前に実行されますか?これは、NOLOCKヒントを削除するとエラーが停止することを意味しますか?

3
kanu

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 COMMITTEDSNAPSHOT分離、またはSERIALIZABLEのみであると結論付ける人もいます。

これらのうち、通常、row-versioning READ COMMITTEDが最も簡単に移行できます。行バージョンの分離レベルの詳細については、 このBooks Onlineトピック とそのサブツリーを参照してください。

6
Paul White 9