2009-04-21 6 views
0

この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

ロックはロックを呼び出すか、ロックで選択してコミットまたはロールバックしたときに行われます。

他のプロシージャが最初にT3でロックされ、その後にT1またはT2でロックされると、デッドロックが発生する可能性があります。次に、2つのトランザクションがお互いにリソースを獲得するのを待っていて、他のトランザクションはロックしています。

テーブルロックを回避し、分離レベルをシリアライズ可能にすることもできます。

+0

+1はシリアライズ可能モードに言及しています。細かい粒度の行レベル・ロックは、デッドロックの影響を受けにくいです。 –

+0

はい、テーブルロックは実際にはパフォーマンスが悪いということではありませんが、正しく動作させるための唯一のソリューションであれば、それは解決策です。 –

0

ロックの問題は、ロックしているすべての場所を同時に調べる必要があることです。問題を多くの小さなものに分離して分割し、個別に調べる方法はありません。

たとえば、他のコードが同じテーブルをロックしていても、それが明白でなく、間違った順序でロックされている場合はどうなりますか?それはデッドロックを引き起こします。

デッドロックが検出された瞬間にサーバーの状態を分析して、現在実行中の他のものを把握する必要があります。それだけでそれを修正しようとすることができます。

3

テーブルロックを使用すると、デッドロックが発生する可能性が高くなります。デッドロックはすべて、順序外操作によって発生するわけではありません。ロックを試みるだけの他のアクティビティ単一のレコードを完全にロックしているので、テーブル全体をロックすると、競合が発生する可能性が高くなります。直列化可能な分離レベルを使用する場合、範囲ロックは索引行に置かれます。これは、同じプロシージャからの2つの並行操作によってデッドロックを引き起こす可能性のある方法で、他のSQL操作による挿入/削除を防止できます。 opsが同じ順序で...

デッドロックを引き起こす原因を正確に特定するには、SQL Serverトレースフラグ1204および1222を設定します。これにより、詳細情報がSQL Serverログに書き込まれますどのステートメントが含まれていたかを含むデッドロック。

Hereはこれを行う方法についての良い記事です。

(終了時にこれらのフラグをオフにすることを忘れないでください)

+0

さらに、これがSQL Server 2005の場合は、プロファイラを使用してデッドロックを記録することができます。 –

関連する問題