1

絶対に起こらないと思っていたデッドロックが発生するアプリケーションで問題が発生しています。2 つのストアド プロシージャがあります。そのうちの 1 つはテーブルの一部を読み取るだけで、そのうちの 1 つはテーブルに行を追加するか、主キー違反がある場合は既存の行を更新します。

ストアド プロシージャが共有読み取りロックを取得できること、および両方のストアド プロシージャが排他ロックに昇格するとデッドロックが発生することについて読んだことがあります。GetList ストアド プロシージャは読み取りのみで書き込みは行わないため、ここでは発生していません。これらのストアド プロシージャがデッドロックする他の原因はありますか?

デッドロックに関する次のレポート:

<?xml version="1.0" encoding="UTF-8"?>
<deadlock-list>
   <deadlock victim="process3e37f62c8">
      <process-list>
         <process id="process3e37f62c8" taskpriority="0" logused="0" waitresource="KEY: 7:72057594152681472 (de2613e7782e)" waittime="2535" ownerId="7732055781" transactionname="SELECT" lasttranstarted="2014-03-17T17:48:31.437" XDES="0x1298bc1c0" lockMode="S" schedulerid="11" kpid="21372" status="suspended" spid="121" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2014-03-17T17:48:31.437" lastbatchcompleted="2014-03-17T17:48:31.437" clientapp=".Net SqlClient Data Provider" hostname="STO2AP07" hostpid="4908" loginname="(hidden)" isolationlevel="read committed (2)" xactid="7732055781" currentdb="7" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
            <executionStack>
               <frame procname="(hidden).dbo.GetList" line="18" stmtstart="1060" stmtend="1942" sqlhandle="0x03000700072cfd1b7b8be800cfa200000100000000000000">
                   SELECT 
                        TOP (@NumRows)
                        [T1].[Id] , 
                        [T1].[A] , 
                        [T1].[B] , 
                        [T1].[C] , 
                        [T1].[D] , 
                        [T1].[E] , 
                        [T1].[F] , 
                        [T1].[G] , 
                        [T1].[H] , 
                        [T1].[I] , 
                        [T1].[J] 
                    FROM [Item] AS [T1] where [J] > @LastUpdatedDateTime ORDER BY [T1].[LastUpdatedField] ASC
                </frame>
            </executionStack>
            <inputbuf>Proc [Database Id = 7 Object Id = 469576711]</inputbuf>
         </process>
         <process id="process5a514c8" taskpriority="0" logused="244" waitresource="KEY: 7:72057594152615936 (16f70bd264f5)" waittime="2535" ownerId="7732055725" transactionname="user_transaction" lasttranstarted="2014-03-17T17:48:31.437" XDES="0x6602dfa00" lockMode="X" schedulerid="13" kpid="21196" status="suspended" spid="267" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-03-17T17:48:31.437" lastbatchcompleted="2014-03-17T17:48:31.437" clientapp=".Net SqlClient Data Provider" hostname="STO2AP07" hostpid="4908" loginname="(hidden)" isolationlevel="read committed (2)" xactid="7732055725" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
               <frame procname="(hidden).dbo.AddToList" line="52" stmtstart="2484" stmtend="3294" sqlhandle="0x030007005cbf2019598be800cfa200000100000000000000">
                    UPDATE [Item] 
                    SET 
                        [A] = @A , 
                        [B] = @B , 
                        [C] = @C , 
                        [D] = @D , 
                        [E] = @E , 
                        [F] = @F , 
                        [G] = @G , 
                        [H] = @H , 
                        [I] = @I ,
                        [J] = @J 
                    WHERE [Id] = @Id
                </frame>
            </executionStack>
            <inputbuf>Proc [Database Id = 7 Object Id = 421576540]</inputbuf>
         </process>
      </process-list>
      <resource-list>
         <keylock hobtid="72057594152681472" dbid="7" objectname="(hidden).dbo.Item" indexname="PK_Item_1" id="lock47c381b80" mode="X" associatedObjectId="72057594152681472">
            <owner-list>
               <owner id="process5a514c8" mode="X" />
            </owner-list>
            <waiter-list>
               <waiter id="process3e37f62c8" mode="S" requestType="wait" />
            </waiter-list>
         </keylock>
         <keylock hobtid="72057594152615936" dbid="7" objectname="(hidden).dbo.Item" indexname="IX_LastUpdatedField" id="lock402a95800" mode="S" associatedObjectId="72057594152615936">
            <owner-list>
               <owner id="process3e37f62c8" mode="S" />
            </owner-list>
            <waiter-list>
               <waiter id="process5a514c8" mode="X" requestType="wait" />
            </waiter-list>
         </keylock>
      </resource-list>
   </deadlock>
</deadlock-list>

以下は、GetList という名前のストアド プロシージャです。

ALTER PROCEDURE [dbo].[GetList]
    @LastUpdatedDateTime datetime,
    @NumRows int
WITH RECOMPILE
AS
BEGIN
    SET NOCOUNT ON;

    SELECT TOP (@NumRows)
           [T1].[Id]
         , [T1].[A]
         , [T1].[B]
         , [T1].[C]
         , [T1].[D]
         , [T1].[E]
         , [T1].[F]
         , [T1].[G]
         , [T1].[H]
         , [T1].[I]
         , [T1].[J]
      FROM [Item] AS [T1] where J >= @LastUpdatedDateTime
  ORDER BY [T1].[J] ASC
END

以下は、AddToList という名前のストアド プロシージャです。

ALTER PROCEDURE [dbo].[AddToList]
    @Id int,
    @A varchar(30),
    @B decimal(18,2),
    @V varchar(30),
    @D varchar(512),
    @E datetime,
    @F datetime,
    @G bit,
    @H int,
    @I int
    @J datetime,
AS
IF NOT EXISTS(SELECT Id FROM Item WHERE [Id] = @Id)
    BEGIN
        SET NOCOUNT ON;
        INSERT INTO [Item] 
                  ( [Id] 
                  , [A]
                  , [B]
                  , [C]
                  , [D]
                  , [E]
                  , [F]
                  , [G]
                  , [H]
                  , [I]
                  , [J]
                  )
             VALUES
                  ( @Id
                  , @A
                  , @B
                  , @C
                  , @D
                  , @E
                  , @F
                  , @G
                  , @H
                  , @I
                  , @J
                  )
    END
ELSE
    BEGIN
        UPDATE [Item] SET
                   [A] = @A
                  , [B] = @B
                  , [C] = @C
                  , [D] = @D
                  , [E] = @E
                  , [F] = @F
                  , [G] = @G
                  , [H] = @H
                  , [I] = @I
                  , [J] = @J
        WHERE [Id] = @Id
    END
4

1 に答える 1

2

選択はこれを行います:

  1. LastUpdatedDateTime インデックスから読み取る (S ロック)
  2. 対応する CI 行を検索します (S ロック)

アップデートはこれを行います:

  1. CI への書き込み (X ロック)
  2. LastUpdatedDateTime インデックスへの書き込み (X ロック)

それらは、互換性のない逆の順序で 2 つのリソースにアクセスします。デッドロック。

リーダーは よりも高い分離レベルで実行されていREAD COMMITTEDますか? READ COMMITTEDロックされた行を読み取った直後にロックを解放する必要があります。

読み取りトランザクションでスナップショット分離モデルを使用できる場合、デッドロックは単純で信頼性が高く永続的な方法で解消されます。

それが不可能な場合は、READ COMMITTED分離レベルを使用してください。

それが不可能な場合は、ロックのヒントをいじる (保守が難しい) か、デッドロックの再試行ロジックを実装する必要があります。

于 2014-03-19T13:35:11.427 に答える