【发布时间】:2013-12-11 19:51:07
【问题描述】:
在 Trace flag 1222 的帮助下,我对处理和解决死锁有了很好的处理,TABLOCKX 也很有帮助。我看到一个新的死锁,我不明白它为什么会死锁,以及如何解决它。我使用的是 SQL Server 2008 R2,10.50.2861.0。
这个单一的语句本身就在一个事务中(我意识到不需要显式的 BEGIN/COMMIT 语句)。根据死锁跟踪(标志 1222),此语句正在锁定 TableB,试图获得锁定 TableA。 TableC 无关紧要。
我原以为 SQL Server 在获得TableA 和TableB 的独占表锁之前不会开始处理此语句。如果它这样做了,我希望它推迟做任何事情(被阻止),直到它可以在两个表上获得排他锁。相反,SQL Server 似乎在到达 TableA 之前开始读取 TableB(并锁定它),然后当它到达 TableA 时,它发现自己与另一个进程(不同的 SQL 语句)死锁锁定了TableA,并且其他进程正在尝试将数据插入TableB。这个其他进程没有使用任何 TABLOCKX。
我对此的解释正确吗?如何让 SQL Server 在运行此语句之前锁定两个表以避免死锁?
UPDATE a
SET StatusId = 9,
StatusLastUpdatedOn = GETDATE()
FROM dbo.TableA AS a WITH (TABLOCKX)
INNER JOIN dbo.TableC AS c ON c.StatusId = a.StatusId
WHERE c.IsComplete = 0
AND a.StatusId NOT IN (1, 3)
AND EXISTS
(
SELECT *
FROM dbo.TableB AS b WITH (TABLOCKX)
WHERE b.Value1 = a.Value1
AND b.ConditionA = 1
);
编辑,根据@Bogdan Sahlean 的请求,以下是 TF1222 输出 - 缩写较长的语句。上面的 UPDATE 语句是 process4583288。它与 process459d708 陷入僵局。上面的 UPDATE 语句 (process4583288) 似乎是 TableB 的所有者,正在等待访问 TableA。
12/11/2013 13:11:09,spid19s,Unknown,waiter id=process459d708 mode=IS requestType=wait
12/11/2013 13:11:09,spid19s,Unknown,waiter-list
12/11/2013 13:11:09,spid19s,Unknown,owner id=process4583288 mode=X
12/11/2013 13:11:09,spid19s,Unknown,owner-list
12/11/2013 13:11:09,spid19s,Unknown,objectlock lockPartition=0 objid=980471563 subresource=FULL dbid=11 objectname=dbname.dbo.TableB id=lock9e7bc880 mode=X associatedObjectId=980471563
12/11/2013 13:11:09,spid19s,Unknown,waiter id=process4583288 mode=X requestType=wait
12/11/2013 13:11:09,spid19s,Unknown,waiter-list
12/11/2013 13:11:09,spid19s,Unknown,owner id=process459d708 mode=IX
12/11/2013 13:11:09,spid19s,Unknown,owner-list
12/11/2013 13:11:09,spid19s,Unknown,objectlock lockPartition=0 objid=353147353 subresource=FULL dbid=11 objectname=dbname.dbo.TableA id=lock3f439dc80 mode=IX associatedObjectId=353147353
12/11/2013 13:11:09,spid19s,Unknown,resource-list
12/11/2013 13:11:09,spid19s,Unknown,Proc [Database Id = 11 Object Id = 1385795344]
12/11/2013 13:11:09,spid19s,Unknown,inputbuf
12/11/2013 13:11:09,spid19s,Unknown,EXEC dbo.usp_ProcedureB;
12/11/2013 13:11:09,spid19s,Unknown,frame procname=dbname.dbo.usp_ProcedureD line=127 stmtstart=6586 stmtend=7022 sqlhandle=0x03000b00108f9952edd5580183a200000100000000000000
12/11/2013 13:11:09,spid19s,Unknown,*** This is the INSERT statement that is deadlocking with the UPDATE statement posted in the Stackoverflow Question - shortened ***
12/11/2013 13:11:09,spid19s,Unknown,frame procname=dbname.dbo.usp_ProcedureB line=119 stmtstart=4972 stmtend=9598 sqlhandle=0x03000b00eb973e0a22e7ee007da200000100000000000000
12/11/2013 13:11:09,spid19s,Unknown,executionStack
12/11/2013 13:11:09,spid19s,Unknown,process id=process459d708 taskpriority=0 logused=236 waitresource=OBJECT: 11:980471563:0 waittime=2127 ownerId=23648431472 transactionname=user_transaction lasttranstarted=2013-12-11T13:11:07.233 XDES=0x27a62c3b0 lockMode=IS schedulerid=4 kpid=2788 status=suspended spid=61 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2013-12-11T13:11:07.233 lastbatchcompleted=2013-12-11T13:11:07.223 clientapp=.Net SqlClient Data Provider hostname=IP-0AF81DC9 hostpid=5388 loginname=some-user isolationlevel=read committed (2) xactid=23648431472 currentdb=11 lockTimeout=4294967295 clientoption1=673185824 clientoption2=128056
12/11/2013 13:11:09,spid19s,Unknown,Proc [Database Id = 11 Object Id = 200150858]
12/11/2013 13:11:09,spid19s,Unknown,inputbuf
12/11/2013 13:11:09,spid19s,Unknown,EXEC dbo.usp_ProcedureA;
12/11/2013 13:11:09,spid19s,Unknown,frame procname=dbname.dbo.usp_ProcedureC line=56 stmtstart=2452 stmtend=2616 sqlhandle=0x03000b004a0fee0be3f6ee007da200000100000000000000
12/11/2013 13:11:09,spid19s,Unknown,*** This is the UPDATE statement Statement Posted in the Stackoverflow Question - shortened ***
12/11/2013 13:11:09,spid19s,Unknown,frame procname=dbname.dbo.usp_ProcedureA line=148 stmtstart=7390 stmtend=8462 sqlhandle=0x03000b00806122731562150182a200000100000000000000
12/11/2013 13:11:09,spid19s,Unknown,executionStack
12/11/2013 13:11:09,spid19s,Unknown,process id=process4583288 taskpriority=0 logused=0 waitresource=OBJECT: 11:353147353:0 waittime=2170 ownerId=23648431512 transactionname=user_transaction lasttranstarted=2013-12-11T13:11:07.240 XDES=0x17d90d950 lockMode=X schedulerid=3 kpid=1164 status=suspended spid=66 sbid=0 ecid=0 priority=0 trancount=2 lastbatchstarted=2013-12-11T13:11:07.030 lastbatchcompleted=2013-12-11T13:11:07.030 clientapp=.Net SqlClient Data Provider hostname=IP-0AF81DC9 hostpid=5388 loginname=some-user isolationlevel=read committed (2) xactid=23648431512 currentdb=11 lockTimeout=4294967295 clientoption1=673185824 clientoption2=128056
12/11/2013 13:11:09,spid19s,Unknown,process-list
12/11/2013 13:11:09,spid19s,Unknown,deadlock victim=process4583288
12/11/2013 13:11:09,spid19s,Unknown,deadlock-list
【问题讨论】:
-
请贴出TF1222的输出。根据这个输出,有人可以说解释是正确还是错误。
-
锁定 X 整个表只是为了避免死锁通常是一个糟糕的解决方案。
-
@Bogdan Sahlean,我编辑了我的问题,包括 TF1222 输出。我了解 TABLOCKX 不是您想要做的第一件事,通常我不会使用它们,但是没有它们,我会在一些经常读取和更新的表上遇到各种死锁,并且大部分解决了它们结合减少事务中的语句数量等,并发现 TABLOCKX 在一些地方提供帮助。比起死锁,我宁愿有少量的阻塞。
-
TABLOCKX 对并发有负面影响。此提示将独占锁定整个表。这可能会删除一些 DL,但这并不意味着这是解决方案。这只是一种避免真正问题而不是消除问题的方法。
-
您能否发布这两个存储过程的执行计划(估计的或更好的实际执行计划):EXEC dbo.usp_ProcedureB & EXEC dbo.usp_ProcedureA?
标签: sql-server sql-server-2008 deadlock