2

時々デッドロックする Web アプリケーションに問題があります

関連するクエリは 3 つあります。2 人がテーブルを更新しようとしています

UPDATE AttendanceRoll
SET ErrorFlag = 0
WHERE ContractID = @ContractID
AND DATEPART(month,AttendanceDate) = DATEPART(month,@Month_Beginning)
AND DATEPART(year,AttendanceDate) = DATEPART(year,@Month_Beginning)

そして、1つはテーブルに挿入しようとしています

INSERT INTO AttendanceRoll 
    (AttendanceDate, ContractID, PersonID, 
    StartTime, 
    EndTime, 
    Hours, AbsenceReason,
    UpdateCount, SplitShiftID, ModifiedBy, ModifiedDate)
SELECT   
    @P33,  @P34,  @P35,
    CONVERT(datetime,REPLACE( @P36, '.', ':')),
    CONVERT(datetime,REPLACE( @P37, '.', ':')),
    @P38,  @P39,  
    @P40, 1,  @P41, GETDATE()

デッドロック グラフは、ページ ロックと交換イベントの一種の循環配置を示しており、2 つの更新クエリは同じサーバー プロセス ID を持っています。

この問題を解決する方法について誰かがアイデアを持っている場合は、それを高く評価してください。

誰かがそれを見る必要がある場合に投稿できるデッドロック グラフがあります。

ありがとうカールR

4

5 に答える 5

1

Update クエリの実行にかなりの時間がかかっていますか (たとえば、1 秒以上)? その場合は、クエリを最適化してみてください (つまり、contractid 列にインデックスを配置するなど)。

デッドロックを修正するときに私がいつも最初にやりたいことは、関連するクエリを調整することです。パフォーマンスが大幅に向上すると、クエリが高速化されるだけでなく、デッドロックが発生する可能性が大幅に減少します。

于 2008-12-01T01:38:56.110 に答える
1

-- ホルヘブルゴスの提案の後、それから...

デッドロックの場合、競技者が 2 人しかいないと仮定すると、1 人が犠牲者になり、1 人が完了します。

デッドロック検出をデータ層に組み込み、デッドロックで失敗した操作を再試行させることができます。

異なるテーブル ヒント ロック メカニズムを使用して、競合するリソースの範囲を最小限に抑えます。使用しているSQLバージョンにどれが当てはまるかわかりませんが、MSDNからのものです。http://msdn.microsoft.com/en-us/library/ms187373.aspx

于 2008-12-01T01:42:18.350 に答える
1

デッドロック グラフと関連するワークロードを確認せずに、交換が存在することについての発言に基づいて、おそらく並列処理を含むデッドロックに陥っています。http://msdn.microsoft.com/en-us/library/aa937571(SQL.80).aspx . デッドロック グラフは前回の記事のようになっていますか?

クエリのパラレシムを無効にできますか? 特定のクエリで無効にするヒント OPTION (MAXDOP 1) があります。これをオンにして、それが役立つかどうかを確認してください。http://msdn.microsoft.com/en-us/library/ms181714.aspx

インデックスを最適化すると、そもそも paralesim の必要性がなくなるため、デッドロックが緩和される場合もあります。

于 2008-12-01T01:48:45.340 に答える
1

私はあなたの更新がテーブルスキャンを行っていると推測し、最終的に行ロックをページロックからテーブルロックにエスカレートさせ、挿入が完了するのを防ぎます

行ロックを超えてエスカレートしないように指示する設定があると思います。最初にそれを試してみてください

そうしないと、更新をより効率的にするために、月のデータを分離してインデックスを作成する必要がある場合があります

于 2008-12-01T01:51:36.537 に答える
0

私は通常、SQLサーバーへのすべての呼び出しを次のようにラップします(正確にはこれはコンパイルされませんが、アイデアは得られます):

for (;;) {
    try {
        using (var t = BeginTransaction()) {
            DoTheCall();
            t.Commit();
            return;
        }
    }
    catch (SqlException ex) {
        if (ex.Number != 1205 && ex.Number != 601 && ex.Number != 605)
            throw;
    }
}
于 2010-04-16T18:28:01.857 に答える