我可以使用 rowlock 提示解決死鎖嗎?
我有一個大型刪除儲存過程,並且在刪除不會刪除任何內容的情況下重現了死鎖。
看起來遇到死鎖的儲存過程部分是這樣的(更改了表名):
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
在我看來,兩個刪除操作同時執行並且在嘗試從這個大表中刪除時相互死鎖。對於這些項目,我知道不會有記錄非常大的表 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”切斷了每行的開頭。從我看到的兩個usp_EntityFullDelete 在同一個語句上死鎖 - 一個刪除行 746946 和一個刪除行 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
當我意識到跟踪顯示並行性時,刪除了我之前的答案。
有一個非常徹底的測試這個大警告,您可以通過限制 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 的執行計劃,因此如果它包含可變數量的行,我將切換到臨時表並強制重新編譯(如上所述)。
SQL Server 仍然可以選擇將行鎖升級為表鎖,即使指定了 WITH(ROWLOCK)。這可能取決於許多因素,包括:刪除的行數、事務獲取的總鎖數以及獲取的所有鎖的總記憶體壓力。
Sunil Agarwal 寫了一篇很棒的文章來描述這個過程,可以在這裡找到:http: //blogs.msdn.com/b/sqlserverstorageengine/archive/2006/05/17/lock-escalation.aspx
為了減輕這些 DELETE 語句的影響,您可以做的一件事是分塊執行刪除:
WHILE 1 = 1 BEGIN DELETE TOP(5000) FROM <table> WHERE <condition> IF @@ROWCOUNT = 0 BEGIN BREAK; END END
不幸的是,您最初問題的答案是一個很大的“它取決於”。
編輯(添加查詢以查看鎖定資訊):
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;
我希望這個“幾乎答案”有所幫助,
馬特