このSQL(c#から呼び出された)は、時々デッドロックを引き起こします。 サーバーの負荷が大きくないので、できるだけロックする方法が使用されています。SqlServer、トランザクションのデッドロック、テーブルは実際にロックされていますか?
-- Lock to prevent race-conditions when multiple instances of an application calls this SQL:
BEGIN TRANSACTION
-- Check that no one has inserted the rows in T1 before me, and that T2 is in a valid state (Test1 != null)
IF NOT EXISTS (SELECT TOP 1 1 FROM T1 WITH(HOLDLOCK, TABLOCKX) WHERE FKId IN {0}) AND
NOT EXISTS(SELECT TOP 1 1 FROM T2 WITH(HOLDLOCK, TABLOCKX) WHERE DbID IN {0} AND Test1 IS NOT NULL)
BEGIN
-- Great! Im the first - go insert the row in T1 and update T2 accordingly. Finally write a log to T3
INSERT INTO T1(FKId, Status)
SELECT DbId, {1} FROM T2 WHERE DbId IN {0};
UPDATE T2 SET LastChangedBy = {2}, LastChangedAt = GETDATE() WHERE DbId IN {0};
INSERT INTO T3 (F1, FKId, F3)
SELECT {2}, DbId, GETDATE() FROM T2 WHERE DbId IN {0} ;
END;
-- Select status on the rows so the program can evaluate what just happened
SELECT FKId, Status FROM T1 WHERE FkId IN {0};
COMMIT TRANSACTION
私は、複数のテーブルをロックする必要があると考えています。
テーブルが実際にxlockedされているとき(最初にテーブルを使用するとき)、またはBEGIN TRANSで一度にすべてのテーブルをロックしているときは少し不安です。
+1はシリアライズ可能モードに言及しています。細かい粒度の行レベル・ロックは、デッドロックの影響を受けにくいです。 –
はい、テーブルロックは実際にはパフォーマンスが悪いということではありませんが、正しく動作させるための唯一のソリューションであれば、それは解決策です。 –