A deadlock is a circular blocking chain, where two or more threads are each blocked by the other so that no one can proceed. When the deadlock monitor thread in SQL Server detects a circular blocking chain, it selects one of the participants as a victim, cancels that spid’s current batch, and rolls backs his transaction in order to let the other spids continue with their work. The deadlock victim will get a 1205 error:
Transaction (Process ID 52) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
A deadlock is a special type of blocking scenario, but blocking and deadlocking are not the same thing. Sometimes we have people report that they are experiencing "deadlocking" when they are really only seeing blocking.
With very few exceptions, deadlocks are a natural side effect of blocking, not a SQL Server bug. The typical deadlock solution is either a stored proc/app code tweak, or a schema/indexing change.
Here’s how to troubleshoot deadlocks. These steps apply to most deadlocks, and they’ll allow you to resolve many of them without even having to dig into query plans or other nitty gritty details. What’s that? You like digging into query plans, and have nitty grits for breakfast every morning? OK then, we’ll look at a deadlock scenario from the inside out a bit later. But first, here are the basics:
deadlock-list
deadlock victim=processdceda8
process-list
process id=processdceda8 taskpriority=0 logused=0 waitresource=KEY: 2:72057594051493888 (0400a4427a09) waittime=5000 ownerId=24008914 transactionname=SELECT lasttranstarted=2006-09-08T15:54:22.327 XDES=0x8fd9a848 lockMode=S schedulerid=1 kpid=4404 status=suspended spid=54 sbid=0 ecid=0 priority=0 transcount=0 lastbatchstarted=2006-09-08T15:54:22.293 lastbatchcompleted=2006-09-08T15:54:22.293 clientapp=OSQL-32 hostname=BARTD2 hostpid=3408 loginname=bartd isolationlevel=read committed (2) xactid=24008914 currentdb=2 lockTimeout=4294967295 clientoption1=538968096 clientoption2=128056
executionStack
frame procname=tempdb.dbo.p1 line=2 stmtstart=60 sqlhandle=0x03000200268be70bd
SELECT c2, c3 FROM t1 WHERE c2 = @p1
frame procname=adhoc line=2 stmtstart=32 stmtend=52 sqlhandle=0x020000008a4df52d3
EXEC p1 3
inputbuf
process id=process3c54c58 taskpriority=0 logused=16952 waitresource=KEY: 2:72057594051559424 (0900fefcd2fe) waittime=5000 ownerId=24008903 transactionname=UPDATE lasttranstarted=2006-09-08T15:54:22.327 XDES=0x802ecdd0 lockMode=X schedulerid=2 kpid=4420 status=suspended spid=55 sbid=0 ecid=0 priority=0 transcount=2 lastbatchstarted=2006-09-08T15:54:22.327 lastbatchcompleted=2006-09-08T15:54:22.310 clientapp=OSQL-32 hostname=BARTD2 hostpid=2728 loginname=bartd isolationlevel=read committed (2) xactid=24008903 currentdb=2 lockTimeout=4294967295 clientoption1=538968096 clientoption2=128056
frame procname=tempdb.dbo.p2 line=2 stmtstart=58 sqlhandle=0x030002005fafdb0c
UPDATE t1 SET c1 = FLOOR (c1), c2 = FLOOR (c2) WHERE c1 = @p1
frame procname=adhoc line=2 stmtstart=32 stmtend=52 sqlhandle=0x020000006f878816
EXEC p2 3
resource-list
keylock hobtid=72057594051559424 dbid=2 objectname=tempdb.dbo.t1 indexname=idx1 id=lock83642a00 mode=S associatedObjectId=72057594051559424
owner-list
owner id=processdceda8 mode=S
waiter-list
waiter id=process3c54c58 mode=X requestType=wait
keylock hobtid=72057594051493888 dbid=2 objectname=tempdb.dbo.t1 indexname=cidx id=lock83643780 mode=X associatedObjectId=72057594051493888
owner id=process3c54c58 mode=X
waiter id=processdceda8 mode=S requestType=wait
pagelock fileid=1 pageid=95516 dbid=9 objectname="" id=lock177a9e280 mode=IX associatedObjectId=72057596554838016
These are all general recommendations that you can apply to any deadlock without having to really roll up your sleeves and get dirty. If after doing all of this you haven’t resolved it, though, you’ll have to dive a bit deeper and tailor a solution to the specifics of the scenario. Here’s a menu of some common techniques that you can choose from when deciding how best to tackle a deadlock:
1. Begin Transaction
2. Update Part table
2. Update Supplier table
3. Update Supplier table
3. Update Part table
4. Commit Transaction
These two batches may deadlock frequently. If both are about to execute step 3, they may each end up blocked by the other because they both need access to a resource that the other connection locked in step 2.
In a follow-up post I’ll look at a fairly typical deadlock in detail. This will provide an example of what you'd have to do if the 8 high-level steps listed above fail you, forcing you to understand the scenario at a deeper level so that you can craft a custom solution.
(This post series is continued in Deadlock Troubleshooting, Part 2.)
Mike,
I don't think CONTEXT_INFO will help you with your deadlocks. In theory, sp_gettoken/sp_bindsession could prevent a deadlock, assuming that (a) it is appropriate for the two processes involved in the deadlock to share a single transaction, and (b) you are able to make some non-trivial changes to one of the apps to have it enlist in the other app's transaction.
Unless your deadlock involves two connections that are doing different pieces of the same ETL transformation, I doubt (a) would apply to you.
I'm not clear on the details of your situation. Are you trying to load a table that has no indexes while other processes concurrently access the table? If so, this is a recipe for blocking. Any read or modification to a table without indexes will require a table scan, which of course means locking every page or row in the table. That all but guarantees that any query that runs at the same time as your ETL data load will be involved in some sort of blocking. It also means that you are probably getting terrible query plans.
If that isn't your situation, please share some specifics.
Bart
You've been kicked (a good thing) - Trackback from DotNetKicks.com
Thanks Bart.
Bart,
Do you have some time you'd be able to look over some deadlocks we've been having? I've been using your page as a bible and I'm still coming up a bit short ... If you are able to give me a few minutes, I'd really appreciate it. My email is in my bio.
Thanks!
The bindsession (context_info) method worked like a charm.
I had also tried disabling page locks, suspecting lock escalation, which did reduce the deadlocks, but not eliminate completely. The processing time increased enormously. Yuk.
Is there any chance we could get you to visit and present at the PASS-MN (Minneapolis) group in the future?
Firstly I must say a big thank you to Microsoft for the new deadlock trace flag 1222. Compared to the...
Firstly I must say a big thank you to Microsoft for the new deadlock trace flag 1222. Compared to the
Hi bart,
i've been experiencing alot of deadlock with type 'pagelock' such this :
update KMS_SERV_MAST_REC set ACTION_CODE= @P0 , ACTV_GRP_ID= @P1 , ACTV_ID= @P2 , STAFF_ID= @P3 , ICD_CODE= @P4 , ICD_CODE_2= @P5 , ICD_CODE_3= @P6 , ICD_CODE_4= @P7 , ICD_CODE_5= @P8 , CREATED_BY= @P9 , CREATED_DATE= @P10 , LAST_UPD_BY= @P11 , LAST_UPD_DATE= @P12 , actual_date= @P13 , dischrg_home_addr= @P14 , dischrg_summary_notes= @P15 , dischrg_summary_given= @P16 , dismissal_code= @P17 , amendment_type= @P18 , amendment_note= @P19 where MR_NO= @P20 and MR_DATE= @P21 and MR_TYPE= @P22 and MR_SEQ= @P23
(@P0 nvarchar(4000),@P1 bigint,@P2 int,@P3 nvarchar(4000),@P4 nvarchar(4000),@P5 nvarchar(4000),@P6 nvarchar(4000),@P7 nvarchar(4000),@P8 nvarchar(4000),@P9 nvarchar(4000),@P10 datetime,@P11 nvarchar(4000),@P12 datetime,@P13 datetime,@P14 nvarchar(4000),@P15 nvarchar(4000),@P16 nvarchar(4000),@P17 nvarchar(4000),@P18 nvarchar(4000),@P19 nvarchar(4000),@P20 nvarchar(4000),@P21 datetime,@P22 nvarchar(4000),@P23 int)update KMS_SERV_MAST_REC set ACTION_CODE= @P0 , ACTV_GRP_ID= @P1 , ACTV_ID= @P2 , STAFF_ID= @P3 , ICD_CODE= @P4 , ICD_CODE_2= @P5 , ICD_CODE_3= @P6 , ICD_CODE_4= @P7 , ICD_CODE_5= @P8 , CREATED_BY= @P9 , CREATED_DATE= @P10 , LAST_UPD_BY= @P11 , LAST_UPD_DATE= @P12 , actual_date= @P13 , dischrg_home_addr= @P14 , dischrg_summary_notes= @P15 , dischrg_summary_given= @P16 , dismissal_code= @P17 , amendment_type= @P18 , amendment_note= @P19 where MR_NO= @P20 and MR_DATE= @P21 and MR_TYPE= @P22 and MR_SEQ= @P23
process id=processbc44d8 taskpriority=0 logused=0 waitresource=PAGE: 5:1:26310 waittime=687 ownerId=53109491 transactionname=implicit_transaction lasttranstarted=2008-07-03T11:07:22.770 XDES=0x3d7ebe8 lockMode=U schedulerid=4 kpid=4964 status=suspended spid=59 sbid=0 ecid=0 priority=0 transcount=2 lastbatchstarted=2008-07-03T11:07:22.787 lastbatchcompleted=2008-07-03T11:07:22.787 clientapp=jTDS hostname=GRSMED1 hostpid=123 loginname=kmsappl isolationlevel=read committed (2) xactid=53109491 currentdb=5 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128058
frame procname=adhoc line=1 stmtstart=834 sqlhandle=0x02000000531ade3a7674bac5a6157116168d0d92c2150219
pagelock fileid=1 pageid=26310 dbid=5 objectname=kms30prod002.kms.KMS_SERV_MAST_REC id=lock2be86740 mode=IX associatedObjectId=72057594063421440
owner id=process88b1f8 mode=IX
waiter id=processbc44d8 mode=U requestType=wait
pagelock fileid=1 pageid=17123 dbid=5 objectname=kms30prod002.kms.KMS_SERV_MAST_REC id=lock30e08b40 mode=U associatedObjectId=72057594063421440
owner id=processbc44d8 mode=U
waiter id=process88b1f8 mode=U requestType=wait
Do you have any idea whats going on ?
I wonder if i used ROWLOCK hint on my update statement will resolved this deadlock ?
Thanks in advance
Rony -
Page locks are usually an indication of a table or index scan. The best solution is probably to tune your UPDATE statement so that there is a more efficient access path to the qualifying rows. Review the steps in this blog post; did you run the query through Database Engine Tuning Advisor? It might have recommended a better index. If DTA didn't make any recommendations, consider an index on MR_NO, MR_DATE, MR_TYPE, and MR_SEQ.
HTH,
Hi Bart,
Thanks for your answer, i already run the query through database engine tuning advisor and yes DTA didnt make any recommendations, i forgot to tell you that MR_NO, MR_DATE, MR_TYPE and MR_SEQ are primary key, so all of these column is already indexed i think.
Any other suggestions bart ?
I'll try to see whether i can change the UPDATE statement and see if there is a more efficient acces path to the qualifying rows
Rony
I've received a couple of questions in email and in comments about deadlocks involving mysterious-sounding
Hi, I could no able trace dead lock information Profiler, even though there was dead lock issue happend from Application level. I turn on the trace flags 1222, 1204 using DBCC in SQL Query Analyser.
Please suggest how to trace dead lock information?
Satish -
1. What is the exact text of the error message you received in the application?
2. What is the exact text of the DBCC command you ran to turn on the trace flags?
3. Were you expecting to find the trace flag output in Profiler? If so, re-read this article.
4. Were the trace flags turned on at the time of the deadlock error? They must be on *before* the deadlock occurs.
5. Did you restart the SQL Server service? A trace flag enabled via DBCC TRACEON will be turned off when you restart the service.
6. Try running "DBCC TRACESTATUS (-1)" to see what trace flags are currently enabled.
HTH -
Although the best known deadlock scenario involves two connections modifying two tables in different
Very interestings posts (the three ones).
In my case I have deadlocks occuring during the syncrhonisation of pull subscribers of our merge replication (sql 2005).
The trace is showing us system stored procedures of the merge replication involved in the deadlock. What are we supposed to do in that case ? To send these post to MS ? :-)
Here is the trace. What would be the actions to do ?
2009-01-14 15:47:19.89 spid16s deadlock-list
2009-01-14 15:47:19.89 spid16s deadlock victim=process928e38
2009-01-14 15:47:19.89 spid16s process-list
2009-01-14 15:47:19.89 spid16s process id=process928e38 taskpriority=5 logused=57720 waitresource=KEY: 7:72057595096006656 (de008218ea30) waittime=3343 ownerId=172382185 transactionname=user_transaction lasttranstarted=2009-01-14T15:47:16.470 XDES=0xdae3258 lockMode=U schedulerid=2 kpid=3184 status=suspended spid=166 sbid=0 ecid=0 priority=-5 transcount=2 lastbatchstarted=2009-01-14T15:47:16.410 lastbatchcompleted=2009-01-14T15:47:16.393 clientapp=900SE66\SQLPROD2008-saretec-PubSesame-901RA01\SQLEXPRESS-27 hostname=667 hostpid=5932 loginname=sa isolationlevel=read committed (2) xactid=172382185 currentdb=7 lockTimeout=4294967295 clientoption1=673384544 clientoption2=128024
2009-01-14 15:47:19.89 spid16s executionStack
2009-01-14 15:47:19.89 spid16s frame procname=mssqlsystemresource.sys.sp_MSmakegeneration line=489 stmtstart=44260 stmtend=44598 sqlhandle=0x0300ff7f587a2f069f52ee00bb9900000100000000000000
2009-01-14 15:47:19.89 spid16s update dbo.MSmerge_genhistory with (rowlock)
2009-01-14 15:47:19.89 spid16s set genstatus = 1,
2009-01-14 15:47:19.89 spid16s guidsrc = newid(),
2009-01-14 15:47:19.89 spid16s coldate = getdate()
2009-01-14 15:47:19.89 spid16s where genstatus = 3
2009-01-14 15:47:19.89 spid16s inputbuf
2009-01-14 15:47:19.89 spid16s Proc [Database Id = 32767 Object Id = 103774808]
2009-01-14 15:47:19.89 spid16s process id=process929d38 taskpriority=0 logused=2668 waitresource=KEY: 7:72057595095810048 (c4026ce1c0d6) waittime=3390 ownerId=172382289 transactionname=UPDATE lasttranstarted=2009-01-14T15:47:16.487 XDES=0xb97ef40 lockMode=X schedulerid=2 kpid=2292 status=suspended spid=108 sbid=0 ecid=0 priority=0 transcount=2 lastbatchstarted=2009-01-14T15:47:16.487 lastbatchcompleted=2009-01-14T15:47:16.487 clientapp=.Net SqlClient Data Provider hostname=018PA01 hostpid=3420 loginname=sa isolationlevel=read committed (2) xactid=172382289 currentdb=7 lockTimeout=4294967295 clientoption1=673316896 clientoption2=128056
2009-01-14 15:47:19.89 spid16s frame procname=saretec.dbo.MSmerge_upd_1F5733FC149A4CBEA3E79A56B5BDD635 line=98 stmtstart=8862 stmtend=10288 sqlhandle=0x030007007da2e90011d07801719b00000000000000000000
2009-01-14 15:47:19.89 spid16s update dbo.MSmerge_ctsv_1F5733FC149A4CBEA3E79A56B5BDD635 with (rowlock)
2009-01-14 15:47:19.89 spid16s set lineage = { fn UPDATELINEAGE(lineage, @replnick, @oldmaxversion+1) },
2009-01-14 15:47:19.89 spid16s generation = @newgen,
2009-01-14 15:47:19.89 spid16s partchangegen = case when (@partchange = 1 or @joinchange = 1) then @newgen else partchangegen end,
2009-01-14 15:47:19.89 spid16s colv1 = { fn UPDATECOLVBM(colv1, @replnick, @bm, @missingbm, { fn GETMAXVERSION({ fn UPDATELINEAGE(lineage, @replnick, @oldmaxversion+1) }) }) }
2009-01-14 15:47:19.89 spid16s FROM inserted as I JOIN dbo.MSmerge_ctsv_1F5733FC149A4CBEA3E79A56B5BDD635 as V with (rowlock)
2009-01-14 15:47:19.89 spid16s ON (I.rowguidcol=V.rowguid)
2009-01-14 15:47:19.89 spid16s and V.tablenick = @tablenick
2009-01-14 15:47:19.89 spid16s option (force order, loop join)
2009-01-14 15:47:19.89 spid16s frame procname=saretec.dbo.SES_MissionEtat_Maj line=17 stmtstart=814 stmtend=1114 sqlhandle=0x030007002574f346db9f7901719b00000100000000000000
2009-01-14 15:47:19.89 spid16s UPDATE T_MISSION
2009-01-14 15:47:19.89 spid16s SET INT_ETAT_PRIMAIRE = @INT_ETAT_PRIMAIRE,
2009-01-14 15:47:19.89 spid16s SCD_ETATS_SECONDAIRES = @SCD_ETATS_SECONDAIRES
2009-01-14 15:47:19.89 spid16s WHERE NUMIDT_MIS = @ID_MISSION
2009-01-14 15:47:19.89 spid16s Proc [Database Id = 7 Object Id = 1190360101]
2009-01-14 15:47:19.89 spid16s resource-list
2009-01-14 15:47:19.89 spid16s keylock hobtid=72057595095810048 dbid=7 objectname=saretec.dbo.MSmerge_contents indexname=nc2MSmerge_contents id=lock17ac4800 mode=S associatedObjectId=72057595095810048
2009-01-14 15:47:19.89 spid16s owner-list
2009-01-14 15:47:19.89 spid16s owner id=process928e38 mode=S
2009-01-14 15:47:19.89 spid16s waiter-list
2009-01-14 15:47:19.89 spid16s waiter id=process929d38 mode=X requestType=wait
2009-01-14 15:47:19.89 spid16s keylock hobtid=72057595096006656 dbid=7 objectname=saretec.dbo.MSmerge_genhistory indexname=c1MSmerge_genhistory id=lock18ea6980 mode=X associatedObjectId=72057595096006656
2009-01-14 15:47:19.89 spid16s owner id=process929d38 mode=X
2009-01-14 15:47:19.89 spid16s waiter id=process928e38 mode=U requestType=wait