web-dev-qa-db-ja.com

行ロックのヒントでデッドロックを解決できますか?

大きな削除ストアドプロシージャがあり、削除しても何も削除されない状況でデッドロックを再現しました。

ストアドプロシージャのデッドロックにヒットした部分は次のようでした(テーブル名が変更されました)。

DELETE d
FROM Table1 d
inner join dbo.Table2 orc on orc.id = d.Table2Id
inner join dbo.Table3 orr on orr.id = orc.Table3Id
inner join Table4 oeh on oeh.id = orr.Table4Id
inner join @deleteEntities de on de.id = oeh.EntityId

この大きなテーブルから削除しようとすると、2つの削除が同時に実行されて互いにデッドロックしているように見えます。これらのアイテムの場合、非常に大きなテーブルtable1、table2、table3のレコードはなかったはずです。

これを次のように変更することで修正できるかどうか疑問に思っています。

DELETE d
FROM Table1 d WITH(rowlock)
inner join dbo.Table2 orc on orc.id = d.Table2Id
inner join dbo.Table3 orr on orr.id = orc.Table3Id
inner join Table4 oeh on oeh.id = orr.Table4Id
inner join @deleteEntities de on de.id = oeh.EntityId

Table1は大きなテーブルなので、sql-serverはページ全体をロックし、このヒントは行のみをロックすると考えています。 Table2Id、Table3Id、Table4Idおよびentityidでfkにインデックスを付けていることに注意してください。

ここで説明するようにトレースを有効にしました: http://blogs.msdn.com/b/bartd/archive/2006/09/09/deadlock-troubleshooting_2c00_-part-1.aspx

と:

DBCC TRACEON (1222, -1)

以下は、「2011-08-29 15:46:57.78 spid15s」が各行の先頭を切り取ったログ出力です。 2つのusp_EntityFullDeleteが同じステートメントでデッドロックしていることがわかります。1つは行746946を削除し、もう1つは行628302を削除しています。このトレース出力の分析では正しいですか?これを防ぐのに役立つ他のことはありますか?

deadlock-list
 deadlock victim=process3e9ada8
  process-list
   process id=processbaf048 taskpriority=0 logused=20022 waittime=3890 schedulerid=1 kpid=1304 status=suspended spid=59 sbid=0 ecid=1 priority=0 transcount=0 lastbatchstarted=2011-08-29T15:46:53.263 lastbatchcompleted=2011-08-29T15:46:53.263 clientapp=.Net SqlClient Data Provider hostname=RGDS hostpid=9108 isolationlevel=read committed (2) xactid=1135559188 currentdb=19 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
    executionStack
     frame procname=Bugfixes.dbo.usp_EntityFullDelete line=178 stmtstart=11180 stmtend=11776 sqlhandle=0x030013007b725817b4bfe400499f00000100000000000000
DELETE d
FROM Table1 d
    inner join dbo.Table2 orc on orc.id = d.Table2Id
    inner join dbo.Table3 orr on orr.id = orc.Table3Id
    inner join Table4 oeh on oeh.id = orr.Table4Id
    inner join @deleteEntities de on de.id = oeh.EntityId     
     frame procname=adhoc line=1 sqlhandle=0x01001300ef337933809a04fd000000000000000000000000
exec dbo.usp_EntityFullDelete 746946,0     
    inputbuf
   process id=processbaf588 taskpriority=0 logused=20022 waittime=3906 schedulerid=1 kpid=6244 status=suspended spid=62 sbid=0 ecid=3 priority=0 transcount=0 lastbatchstarted=2011-08-29T15:46:45.637 lastbatchcompleted=2011-08-29T15:46:45.637 clientapp=.Net SqlClient Data Provider hostname=RGDS hostpid=9108 isolationlevel=read committed (2) xactid=1135558120 currentdb=19 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
    executionStack
     frame procname=Bugfixes.dbo.usp_EntityFullDelete line=178 stmtstart=11180 stmtend=11776 sqlhandle=0x030013007b725817b4bfe400499f00000100000000000000
DELETE d
FROM Table1 d
    inner join dbo.Table2 orc on orc.id = d.Table2Id
    inner join dbo.Table3 orr on orr.id = orc.Table3Id
    inner join Table4 oeh on oeh.id = orr.Table4Id
    inner join @deleteEntities de on de.id = oeh.EntityId     
     frame procname=adhoc line=1 sqlhandle=0x01001300fc3e1016609402c4000000000000000000000000
exec dbo.usp_EntityFullDelete 628302,0     
    inputbuf
   process id=process3e9a868 taskpriority=0 logused=580 waitresource=PAGE: 19:1:1942004 waittime=3890 ownerId=1135558120 transactionname=user_transaction lasttranstarted=2011-08-29T15:46:53.053 XDES=0xf2512b30 lockMode=U schedulerid=3 kpid=8808 status=suspended spid=62 sbid=0 ecid=8 priority=0 transcount=0 lastbatchstarted=2011-08-29T15:46:45.637 lastbatchcompleted=2011-08-29T15:46:45.637 clientapp=.Net SqlClient Data Provider hostname=RGDS hostpid=9108 isolationlevel=read committed (2) xactid=1135558120 currentdb=19 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
    executionStack
     frame procname=Bugfixes.dbo.usp_EntityFullDelete line=178 stmtstart=11180 stmtend=11776 sqlhandle=0x030013007b725817b4bfe400499f00000100000000000000
DELETE d
FROM Table1 d
    inner join dbo.Table2 orc on orc.id = d.Table2Id
    inner join dbo.Table3 orr on orr.id = orc.Table3Id
    inner join Table4 oeh on oeh.id = orr.Table4Id
    inner join @deleteEntities de on de.id = oeh.EntityId     
     frame procname=adhoc line=1 sqlhandle=0x01001300fc3e1016609402c4000000000000000000000000
exec dbo.usp_EntityFullDelete 628302,0     
    inputbuf
   process id=process3e9ada8 taskpriority=0 logused=0 waitresource=PAGE: 19:1:1928384 waittime=3765 ownerId=1135559188 transactionname=user_transaction lasttranstarted=2011-08-29T15:46:53.263 XDES=0xf2512d70 lockMode=U schedulerid=3 kpid=9196 status=suspended spid=59 sbid=0 ecid=6 priority=0 transcount=0 lastbatchstarted=2011-08-29T15:46:53.263 lastbatchcompleted=2011-08-29T15:46:53.263 clientapp=.Net SqlClient Data Provider hostname=RGDS hostpid=9108 isolationlevel=read committed (2) xactid=1135559188 currentdb=19 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
    executionStack
     frame procname=Bugfixes.dbo.usp_EntityFullDelete line=178 stmtstart=11180 stmtend=11776 sqlhandle=0x030013007b725817b4bfe400499f00000100000000000000
DELETE d
FROM Table1 d
    inner join dbo.Table2 orc on orc.id = d.Table2Id
    inner join dbo.Table3 orr on orr.id = orc.Table3Id
    inner join Table4 oeh on oeh.id = orr.Table4Id
    inner join @deleteEntities de on de.id = oeh.EntityId     
     frame procname=adhoc line=1 sqlhandle=0x01001300ef337933809a04fd000000000000000000000000
exec dbo.usp_EntityFullDelete 746946,0     
    inputbuf
   process id=process3e9b198 taskpriority=0 logused=20006 waittime=3984 schedulerid=3 kpid=9212 status=suspended spid=59 sbid=0 ecid=0 priority=0 transcount=2 lastbatchstarted=2011-08-29T15:46:53.263 lastbatchcompleted=2011-08-29T15:46:53.263 clientapp=.Net SqlClient Data Provider hostname=RGDS hostpid=9108 loginname=sa isolationlevel=read committed (2) xactid=1135559188 currentdb=19 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
    executionStack
     frame procname=Bugfixes.dbo.usp_EntityFullDelete line=178 stmtstart=11180 stmtend=11776 sqlhandle=0x030013007b725817b4bfe400499f00000100000000000000
DELETE d
FROM Table1 d
    inner join dbo.Table2 orc on orc.id = d.Table2Id
    inner join dbo.Table3 orr on orr.id = orc.Table3Id
    inner join Table4 oeh on oeh.id = orr.Table4Id
    inner join @deleteEntities de on de.id = oeh.EntityId     
     frame procname=adhoc line=1 sqlhandle=0x01001300ef337933809a04fd000000000000000000000000
exec dbo.usp_EntityFullDelete 746946,0     
    inputbuf
exec dbo.usp_EntityFullDelete 746946,0    
   process id=process46b0da8 taskpriority=0 logused=20006 waittime=4000 schedulerid=4 kpid=6596 status=suspended spid=62 sbid=0 ecid=0 priority=0 transcount=2 lastbatchstarted=2011-08-29T15:46:45.637 lastbatchcompleted=2011-08-29T15:46:45.637 clientapp=.Net SqlClient Data Provider hostname=RGDS hostpid=9108 loginname=sa isolationlevel=read committed (2) xactid=1135558120 currentdb=19 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
    executionStack
     frame procname=Bugfixes.dbo.usp_EntityFullDelete line=178 stmtstart=11180 stmtend=11776 sqlhandle=0x030013007b725817b4bfe400499f00000100000000000000
DELETE d
FROM Table1 d
    inner join dbo.Table2 orc on orc.id = d.Table2Id
    inner join dbo.Table3 orr on orr.id = orc.Table3Id
    inner join Table4 oeh on oeh.id = orr.Table4Id
    inner join @deleteEntities de on de.id = oeh.EntityId     
     frame procname=adhoc line=1 sqlhandle=0x01001300fc3e1016609402c4000000000000000000000000
exec dbo.usp_EntityFullDelete 628302,0     
    inputbuf
exec dbo.usp_EntityFullDelete 628302,0    
   process id=process46b1048 taskpriority=0 logused=0 waitresource=PAGE: 19:1:1942003 waittime=3937 ownerId=1135559188 transactionname=user_transaction lasttranstarted=2011-08-29T15:46:53.263 XDES=0xd0224ab0 lockMode=U schedulerid=4 kpid=7892 status=suspended spid=59 sbid=0 ecid=8 priority=0 transcount=0 lastbatchstarted=2011-08-29T15:46:53.263 lastbatchcompleted=2011-08-29T15:46:53.263 clientapp=.Net SqlClient Data Provider hostname=RGDS hostpid=9108 isolationlevel=read committed (2) xactid=1135559188 currentdb=19 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
    executionStack
     frame procname=Bugfixes.dbo.usp_EntityFullDelete line=178 stmtstart=11180 stmtend=11776 sqlhandle=0x030013007b725817b4bfe400499f00000100000000000000
DELETE d
FROM Table1 d
    inner join dbo.Table2 orc on orc.id = d.Table2Id
    inner join dbo.Table3 orr on orr.id = orc.Table3Id
    inner join Table4 oeh on oeh.id = orr.Table4Id
    inner join @deleteEntities de on de.id = oeh.EntityId     
     frame procname=adhoc line=1 sqlhandle=0x01001300ef337933809a04fd000000000000000000000000
exec dbo.usp_EntityFullDelete 746946,0     
    inputbuf
   process id=process46b16d8 taskpriority=0 logused=580 waitresource=PAGE: 19:1:441708 waittime=3937 ownerId=1135558120 transactionname=user_transaction lasttranstarted=2011-08-29T15:46:53.053 XDES=0xd0224870 lockMode=U schedulerid=4 kpid=6676 status=suspended spid=62 sbid=0 ecid=6 priority=0 transcount=0 lastbatchstarted=2011-08-29T15:46:45.637 lastbatchcompleted=2011-08-29T15:46:45.637 clientapp=.Net SqlClient Data Provider hostname=RGDS hostpid=9108 isolationlevel=read committed (2) xactid=1135558120 currentdb=19 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
    executionStack
     frame procname=Bugfixes.dbo.usp_EntityFullDelete line=178 stmtstart=11180 stmtend=11776 sqlhandle=0x030013007b725817b4bfe400499f00000100000000000000
DELETE d
FROM Table1 d
    inner join dbo.Table2 orc on orc.id = d.Table2Id
    inner join dbo.Table3 orr on orr.id = orc.Table3Id
    inner join Table4 oeh on oeh.id = orr.Table4Id
    inner join @deleteEntities de on de.id = oeh.EntityId     
     frame procname=adhoc line=1 sqlhandle=0x01001300fc3e1016609402c4000000000000000000000000
exec dbo.usp_EntityFullDelete 628302,0     
    inputbuf
  resource-list
   pagelock fileid=1 pageid=1928384 dbid=19 objectname=Bugfixes.dbo.Table1 id=lockaef9db80 mode=U associatedObjectId=72057595211284480
    owner-list
     owner id=process46b0da8 mode=U
    waiter-list
     waiter id=process3e9ada8 mode=U requestType=wait
   exchangeEvent id=port80128a00 nodeId=22
    owner-list
     owner event=e_waitNone type=producer id=process3e9ada8
     owner event=e_waitNone type=producer id=process46b1048
    waiter-list
     waiter event=e_waitPortClose type=consumer id=processbaf048
   exchangeEvent id=port80128e20 nodeId=6
    owner-list
     owner event=e_waitNone type=producer id=processbaf048
    waiter-list
     waiter event=e_waitPortOpen type=consumer id=process3e9b198
   pagelock fileid=1 pageid=1942004 dbid=19 objectname=Bugfixes.dbo.Table1 id=lockf3d1f080 mode=U associatedObjectId=72057595211284480
    owner-list
     owner id=process3e9b198 mode=U
    waiter-list
     waiter id=process3e9a868 mode=U requestType=wait
   exchangeEvent id=port80128ed0 nodeId=22
    owner-list
     owner event=e_waitNone type=producer id=process46b16d8
     owner event=e_waitNone type=producer id=process3e9a868
    waiter-list
     waiter event=e_waitPortClose type=consumer id=processbaf588
   exchangeEvent id=port80128320 nodeId=6
    owner-list
     owner event=e_waitNone type=producer id=processbaf588
    waiter-list
     waiter event=e_waitPortOpen type=consumer id=process46b0da8
   pagelock fileid=1 pageid=1942003 dbid=19 objectname=Bugfixes.dbo.Table1 id=lockfbcc1680 mode=U associatedObjectId=72057595211284480
    owner-list
     owner id=process46b0da8 mode=U
    waiter-list
     waiter id=process46b1048 mode=U requestType=wait
   pagelock fileid=1 pageid=441708 dbid=19 objectname=Bugfixes.dbo.Table1 id=lockfc628980 mode=U associatedObjectId=72057595211284480
    owner-list
     owner id=process3e9b198 mode=U
    waiter-list
     waiter id=process46b16d8 mode=U requestType=wait
5
Adam Butler

トレースが並列性を示していることに気付いたときに、以前の回答を削除しました。

これを非常に徹底的にテストするための大きな警告では、MAXDOPを制限し、Table1にUPDLOCKヒントを追加することで、デッドロックを軽減できます。また、(@ Aaronの提案に従って)EXISTSも試します。

DELETE 
    d
FROM 
    Table1 d WITH (UPDLOCK)
INNER JOIN
    #deleteEntities de
ON  de.id = oeh.EntityId 
WHERE EXISTS
    (
    SELECT
        NULL
    FROM
        dbo.Table2 orc 
    INNER JOIN
        dbo.Table3 orr 
    ON  orr.id = orc.Table3Id
    INNER JOIN 
        dbo.Table4 oeh            
    ON  oeh.id = orr.Table4Id
    WHERE
        oeh.id = de.Table2Id
    ) OPTION (MAXDOP 1, RECOMPILE)

これは、大ハンマーアプローチです。適切なインデックス付けで並列処理を排除できる可能性がありますが、実行計画や統計情報が表示されない限り、そのことについてアドバイスすることはできません。

デッドロックトレースの@deleteEntitiesは少し「疑わしい」ものです。あなたは単一の識別子を渡していますが、この一時テーブルはそこにありますか?オプティマイザーは、このために1と推定される実行プランを作成している可能性が高いため、可変数の行が含まれている場合は、一時テーブルに切り替えて強制的に再コンパイルします(上記のとおり)。

4

SQL Serverは、WITH(ROWLOCK)が指定されている場合でも、行ロックをテーブルロックにエスカレートすることを選択できます。これは、削除された行の数、トランザクションによって取得されたロックの合計数、取得されたすべてのロックの合計メモリプレッシャーなど、さまざまな要素に依存します。

Sunil Agarwalはこのプロセスを説明するすばらしい記事を書いています。これは次の場所にあります: http://blogs.msdn.com/b/sqlserverstorageengine/archive/2006/05/17/lock-escalation.aspx =

これらのDELETEステートメントの影響を軽減するためにできることの1つは、チャンクで削除を実行することです。

WHILE 1 = 1
BEGIN
    DELETE TOP(5000)
    FROM <table>
    WHERE <condition>

    IF @@ROWCOUNT = 0
    BEGIN
        BREAK;
    END
END

残念ながら、元の質問への答えは、大きな「それは依存する」です。

EDIT(ロック情報を確認するためのクエリの追加):

SELECT
    DB_NAME([tl].[resource_database_id]) AS [database_name],
    SCHEMA_NAME([o].[schema_id]) + '.' + [o].[name] AS [object_name],
    [tl].[request_type],
    [tl].[request_mode],
    [tl].[request_status]
FROM sys.dm_exec_sessions AS [es]

    INNER JOIN sys.dm_tran_locks AS [tl]
        ON [es].[session_id] = [tl].[request_session_id]    

        INNER JOIN sys.objects AS [o]
            ON [tl].[resource_associated_entity_id] = [o].[object_id]

WHERE [es].[is_user_process] = 1;

この「ほぼ答え」が役に立てば幸い

マット

3
Matt M