2

アプリケーションでブックマーク ルックアップのデッドロックが検出されました。使用する解決策を決定できません。それらのどれも最適ではないようです。

クエリは次のとおりです。

 UPDATE TEST SET DATA = @data WHERE CATEGORY = @cat

 SELECT DATA, EXTRA_COLUMN FROM TEST WHERE CATEGORY = @cat

問題は、クラスター化インデックスと逆の順序で両方のクエリで使用される CATEGORY と DATA に非クラスター化インデックスがあることです。

つまり、更新はクラスター化インデックスをロックしてテーブルを更新しますが、選択はクラスター化されていないインデックスをロックしてブックマークの検索を行い、両方がお互いにロックすることを望んでいます (デッドロック)。

私が見つけたオプションは次のとおりです。

1 - 選択クエリのすべての列を含むインデックスを作成します。- うまくいきましたが、良い考えだとは思いません。アプリケーションのどこでも更新できる選択クエリで使用される列を含める必要があります。

2 - データベースのトランザクション分離レベルを COMMITTED_SNAPSHOT に変更します

3 - 選択に NOLOCK ヒントを追加します

4 - インデックスを削除する

5 - 他のトランザクションをブロックすることになるロックを取得する機会が得られる前に、トランザクションの 1 つを早い時点で強制的にブロックします。(動作しませんでした)

2 番目のオプションが最良の選択だと思いますが、他の問題が発生する可能性があることはわかっています。COMMITTED_SNAPSHOT を SQL SERVER の既定の分離レベルにするべきではありませんか?

アプリケーションにもデータベース ロジックにもエラーはないように思えます。これは、非クラスター化インデックスを持つ 1 つの単純なテーブルと、同じテーブルにアクセスする 2 つのクエリ (1 つは更新用、もう 1 つは選択用) です。

この問題を解決する最良の方法はどれですか? 他の解決策はありますか?

SQL Server が単独で解決できることを本当に期待していました。

4

2 に答える 2

1

カテゴリ (データと Extra_Column を含む) に非クラスター化インデックスを追加し、次のヒントをクエリに追加してみてください。

UPDATE t SET t.DATA = @data FROM TEST WITH (index(ix_Cat)) WHERE CATEGORY = @cat

SELECT DATA, EXTRA_COLUMN FROM TEST WITH (index(ix_Cat)) WHERE CATEGORY = @cat

これにより、両方のクエリが同じ順序でデータを更新/選択し、それらが互いにデッドロックするのを防ぐことができます。

于 2015-04-20T20:19:28.673 に答える
1

スナップショット分離は、式から読み取りを削除するための非常に堅牢なソリューションです。多くの RDBMS では、それらが常にオンになっています。それらは実際には多くの問題を引き起こしません。非常に具体的なインデックスやヒントなどの手動の脆弱なソリューションよりも、このソリューションを優先してください。

于 2015-04-20T20:20:09.143 に答える