web-dev-qa-db-ja.com

SQL Server SELECTステートメントによりブロッキングが発生する

SQL Server 2005データベース(行のバージョン管理なし)を使用して巨大なselectステートメントを実行しており、他のステートメントの実行をブロックしていることがわかります(sp_who2)。 SELECTステートメントがブロッキングを引き起こす可能性があることに気付きませんでした。これを軽減するために何かできることはありますか?

17
Neil Barnwell

SELECTは更新をブロックできます。適切に設計されたデータモデルとクエリは、最小限のブロッキングを引き起こすだけで、問題にはなりません。 「通常の」WITH NOLOCKヒントは、ほとんど常に間違った答えです。適切な答えは、巨大なテーブルをスキャンしないようにクエリを調整することです。

クエリを調整できない場合は、まず SNAPSHOT ISOLATION level を検討する必要があります。次に、 DATABASE SNAPSHOTS の使用を検討する必要があります。最後のオプションはDIRTY READSである必要があります(変更することをお勧めします- 分離レベル NOLOCK HINTを使用するのではなく)。名前が明確に示すように、ダーティリードは一貫性のないデータを返します(たとえば、シート全体のバランスが取れていない可能性があります)。

32
Remus Rusanu

documentation から:

Shared (S)ロックを使用すると、同時トランザクションで、悲観的同時実行制御のもとで_(SELECT)_リソースを読み取ることができます。詳細については、_Types of Concurrency Control_を参照してください。リソースにshared (S)ロックが存在する間、他のトランザクションはデータを変更できません。 Shared (S)リソースのロックは、トランザクション分離レベルが反復可能読み取り以上に設定されていない限り、またはロックヒントを使用してshared (S)を保持しない限り、読み取り操作が完了するとすぐに解放されます。トランザクションの期間中のロック。

_shared lock_は、別の共有ロックまたは更新ロックと互換性がありますが、排他ロックとは互換性がありません。

つまり、SELECTクエリはUPDATEおよびINSERTクエリをブロックし、逆も同様です。

SELECTクエリは、テーブルから値のブロックを読み取るときに一時的な共有ロックを設定し、読み取りが完了したらそれを削除します。

ロックが存在する間は、ロックされた領域のデータを使用して何かを行うことはできません。

2つのSELECTクエリが互いにブロックすることは決してありません(それらが_SELECT FOR UPDATE_でない限り)

データベースでSNAPSHOT分離レベルを有効にして使用できますが、UPDATEクエリがSELECTクエリによってロックされるのを防ぐことはできません(これはあなたのケースのようです) )。

ただし、SELECTクエリがUPDATEによってロックされるのを防ぎます。

また、Oracleとは異なり、_SQL Server_はロックマネージャを使用して、メモリ内のリンクリストにロックを保持します。

つまり、負荷の高い状況では、リンクされたリスト自体がトランザクションスレッドによってロックされるため、ロックを配置および削除するだけでは遅くなる可能性があります。

15
Quassnoi

ダーティリードを実行するには、次のいずれかを実行できます。

 using (new TransactionScope(TransactionScopeOption.Required, 
 new TransactionOptions { 
 IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
 {
 //Your code here
 }

または

SelectCommand = "SELECT * FROM Table1 WITH (NOLOCK) INNER JOIN Table2 WITH (NOLOCK) ..."

ダーティリードするすべてのテーブルの後にWITH(NOLOCK)を書き込む必要があることに注意してください。

2
David Espart

デッドロックが発生することもあります。

"1つのテーブルのみを含むデッドロック" http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx

または不正な結果:

「READ COMMITTEDおよびREPEATABLE READで選択すると、誤った結果が返される場合があります。」

http://www2.sqlblog.com/blogs/alexander_kuznetsov/archive/2009/04/10/selects-under-read-committed-and-repeatable-read-may-return-incorrect-results.aspx

0
A-K

WITH(READPAST)テーブルヒントを使用できます。 WITH(NOLOCK)とは異なります。トランザクションが開始される前のデータを取得し、誰もブロックしません。トランザクションが開始される前にステートメントを実行したと想像してください。

SELECT * FROM table1  WITH (READPAST)
0
Senol Cakir

トランザクションレベル をコミットされていない読み取りに設定できます

0
Johnno Nolan