We've been having some blocking problems on SQL Server 2014.
First, let me test my knowledge:
A deadlock, as I understand it, is when process A blocks process B which then also blocks process A, creating a cycle in the graph of blocked processes. It was my understanding that, when this occurs, SQL Server can recognize it and kill one of the processes, the deadlock victim. I assume SQL Server can also recognize a cycle of three or more processes, too, but maybe not?
What's not a deadlock is when a process locks a resource, then some other processes need it and waits for it to become unlocked. If the first process never completes, then the other processes will just wait (until they timeout). SQL Server will not kill any processes in this case because blocking is normal.
Now, are there any kind of deadlocks that SQL Server either can't detect or will choose not to kill?
We have some users running heavy queries, a job that runs every 5 minutes to update the tables, and a second job that runs a small query to check the health of the first job. (It checks the most recent date and sends an email if the data is stale.)
My DBA tells me that some combination of the above three things is creating a deadlock, but that SQL Server won't kill it. Not a normal block, but an actual deadlock. Is that possible?
Best Answer
As an anecdote that may or may not shed some light on your particular issue, we've had a similar problem to this where an external application would execute a stored procedure and improperly roll back when an error was encountered.
This procedure was vendor provided and unable to be modified. Adding to this,
XACT_ABORT
was set to the default value ofOFF
and could not be modified.The application would reach a CommandTimeout event (due to
SqlException
being thrown and the application not handling this appropriately), but the session would remain open.Since
XACT_ABORT
isOFF
and explicit transaction statements were used in the SP without appropriate error handling, the session would maintain any locks held by the aborted procedure. The session itself would be in a "SLEEPING" status with "AWAITING COMMAND".This was a somewhat insidious issue for us, because the failed session would not be immediately obvious. However, contention would rapidly grow in the way that a vehicle stopping in the middle of a busy intersection will cause a multi-car incident. Unrelated applications attempting to access the locked resources held by the now-orphaned session would simply
WAIT
, entering aSUSPENDED
status while potentially holding locks of their own, creating a scenario of branching contention and lock escalation.While there are certainly other methods, this was a very busy application database which limited the usefulness of more direct methods which would have been optimal in a more controlled or quieter environment. In order to quickly and easily identify the ROOT session responsible, we cobbled together the following query, which returns the contention "tree" and allowed us to
KILL
the offending session (once appropriately identified).To add some explanation to this:
ROOT
is obviously the orphaned session and should beKILL
ed.LEAF
is a blocked session which is not, itself, blocking other transactions.BRANCH
is a blocked session which, due to its own locks, is blocking another session--either anotherBRANCH
in the chain, or aLEAF
(terminal).The use of returning our
sql_handle
text as an XMLprocessing-instruction
may seem odd, but was deliberate to circumvent truncation, preserve formatting, and bypass the need to explicitly escape characters.