3

最近、一部のコードを C# から SQL (SQL Server 2005) に移動して、同時実行の問題を回避しようとしました。ただし、SQL ではデッドロックが発生しています。デッドロックを取得する手順を再作成することはできませんが、SQL トレースでキャプチャできました。

テーブルにはトリガーはありませんが、検索をサポートするためのインデックスがいくつかあります。

トレースによると、デッドロックは、同じレコードで同じ update ステートメントを実行している 2 人のユーザーによって引き起こされています。

UPDATE myTable
SET
  col2 = @var2 + col2
  ,col3 = CASE WHEN (@Var2 <= 0 OR @Var2 + Col2 <= 0)
            THEN Col3
          ELSE
            CONVERT
            (
               dbo.MoneyInfo,
               @var3 + ':' + @Var4 + ':' + @Var5
            )
          END
OUTPUT INSERTED.Col0,
       Inserted.Col2,
       Inserted.Col3
WHERE Col0 = @Var1

dbo.MoneyInfoカスタム CLR 型です。テーブルは次のようになります。

create table myTable
(
    col0 int,
    col1 int,
    col2 decimal(18,2),
    col3 dbo.MoneyInfo
)

Col0 はクラスター化されていない主キー (PK_Stock)、col1 はクラスター化されたインデックス (IX_Item) です。

これは、トレースからのデッドロック グラフです。

デッドロック グラフ

まったく同じストアド プロシージャ ステートメントを実行している 2 人のユーザーが、同じステートメントでデッドロックに陥る可能性があることを理解できません。最初の接続がレコードをロックして、2 番目の接続が使用可能になるまで待機するように強制するべきではありませんか? このデッドロックの原因を調べることができるものは他にありますか? OUTPUT ステートメントが原因でしょうか。

4

1 に答える 1

1

はい、2人が最初の実行をロックアウトせずに同じステートメントを実行する可能性があります。私も同じシナリオを生成しました。SQLダーティ読み取りの問題。これに対する解決策は、 ISOLATION LEVELREADCOMMITTEDトランザクションを使用して提供されました。ステートメントは、変更されたが他のトランザクションによってコミットされていないデータを読み取ることができないことを指定します。これにより、ダーティリードが防止されます。データは、現在のトランザクション内の個々のステートメント間の他のトランザクションによって変更される可能性があり、その結果、繰り返し不可能な読み取りまたはファントムデータが発生します。詳細については、Microsoftナレッジベース[http://msdn.microsoft.com/en-us/library/ms173763.aspx]を参照してください。

要約:-クエリをトランザクションに入れるだけです[優先-分離レベルはコミットされたトランザクションを読み取ります]

于 2012-05-29T07:51:44.370 に答える