ライブアプリでデッドロックエラーが発生し、(SQL Server Profilerの「デッドロックグラフ」を使用after insert
して)テーブルで定義されたトリガーまで追跡しました。
基本的にシナリオはそうです-特定のテーブルに挿入されたレコードを時間枠ごとにグループ化して追跡したいと思います。(つまり、12:00〜12:10の間に、7つのレコードがに挿入されましたUsers
)。
私が実装した方法はafter insert
、これらのテーブルにトリガーを作成することでした。そのため、レコードが挿入されると、統計テーブルの適切なレコードを更新します。(下記参照)。
私が言ったように、これはデッドロック状態を生み出すようです。何が起こるかというと(私はそれについて確信する方法を見つけていないと思います)、各トランザクションがコミットする前にいくつかのテーブルにいくつかのレコードを挿入/更新する可能性があります。
したがって、トランザクション1が実行され、統計テーブルの特定のレコードが更新され(したがってロックされ)、次にテーブルBのレコードが更新されます。
一方、トランザクション2はレコードをテーブルBに挿入し(したがってロックし)、次のことを試みます。統計テーブルのレコードを更新すると、デッドロックが発生します。
(もちろん、これは起こり得ることの非常に単純化されたバージョンです。実際には、私はまだ100%確実ではありません)。
さて、私の最初の考えは、コミット後にトリガーを実行して、トランザクションがロックを保持しないようにすることが可能かどうかを確認することでした。
しかし、私が理解できる限り、そのような選択肢はありません。
別の解決策は、トリガーを完全に排除し、代わりにある種のバッチジョブを使用することです。
望ましい解決策についての他のアイデア/考えは大歓迎です。
トリガーコード:
SELECT @TimeIn = I.TimeIn,
@TimeOut = I.[TimeOut],
FROM Inserted AS I
SET @NoOfPAX = 1
SET @Day = DATEADD(dd,0,DATEDIFF(dd,0,@TimeOut))
SET @HourOfTheDay = DATEPART (HOUR, @TimeOut)
SET @MinuteOfTheHour = DATEPART (MINUTE, @TimeOut)
SELECT @HourlyStatsExists = COUNT(*)
FROM dbo.DataWarehouse_HourlyStats
WHERE [Day] = @Day
AND HourOfTheDay = @HourOfTheDay
AND MinuteOfTheHour = @MinuteOfTheHour
IF @HourlyStatsExists = 0
BEGIN
INSERT INTO dbo.DataWarehouse_HourlyStats
(
HourOfTheDay,
MinuteOfTheHour,
[Day],
Total
)
VALUES (
@HourOfTheDay,
@MinuteOfTheHour,
@Day,
@NoOfPAX
)
END
ELSE
BEGIN
UPDATE DataWarehouse_HourlyStats
SET Total = Total + @NoOfPAX,
LastUpdate = GetDate()
WHERE [Day] = @Day
AND HourOfTheDay = @HourOfTheDay
AND MinuteOfTheHour = @MinuteOfTheHour
END