Pages

Wednesday, April 30, 2014

Deadlock Graph

Find a Deadlock Graph:

SELECT CAST(REPLACE(REPLACE(XEventData.XEvent.value('(data/value)[1]', 'varchar(max)'), '<victim-list>', '<deadlock><victim-list>'), '<process-list>', '</victim-list><process-list>') AS XML) AS DeadlockGraph
FROM (
 SELECT CAST(target_data AS XML) AS TargetData
 FROM sys.dm_xe_session_targets st
 INNER JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
 WHERE NAME = 'system_health'
 ) AS Data
CROSS APPLY TargetData.nodes('//RingBufferTarget/event') AS XEventData(XEvent)
WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report'

Parse Deadlock graph:


DECLARE @deadlock TABLE (
 DeadlockID INT IDENTITY PRIMARY KEY CLUSTERED
 ,DeadlockGraph XML
 );

INSERT INTO @deadlock
VALUES ('');

-- insert the deadlock XML in the above line! Duplicate as necessary for additional graphs.
WITH CTE
AS (
 SELECT DeadlockID
  ,DeadlockGraph
 FROM @deadlock
 )
 ,Process
AS (
 -- get the data from the process node
 SELECT CTE.DeadlockID
  ,
  --[DeadlockTime]=
  CTE.[DeadlockGraph]
  ,[Victim] = CASE 
   WHEN Deadlock.Process.value('@id', 'varchar(50)') = Deadlock.Process.value('/deadlock-list[1]/deadlock[1]/@victim', 'varchar(50)')
    THEN 1
   ELSE 0
   END
  ,[LockMode] = Deadlock.Process.value('@lockMode', 'varchar(3)')
  ,[ClientApp] = Deadlock.Process.value('@clientapp', 'varchar(100)')
  ,[HostName] = Deadlock.Process.value('@hostname', 'varchar(20)')
  ,[LoginName] = Deadlock.Process.value('@loginname', 'varchar(20)')
  ,[TransactionTime] = Deadlock.Process.value('@lasttranstarted', 'datetime')
  ,[BatchStarted] = Deadlock.Process.value('@lastbatchstarted', 'datetime')
  ,[BatchCompleted] = Deadlock.Process.value('@lastbatchcompleted', 'datetime')
  ,[InputBuffer] = Deadlock.Process.value('inputbuf[1]', 'varchar(1000)')
  ,[ProcessID] = Deadlock.Process.value('@id', 'varchar(50)')
  ,[SPID] = Deadlock.Process.value('@spid', 'int')
  ,-- server process id
  [SBID] = Deadlock.Process.value('@sbid', 'int')
  ,-- server batch id
  [ECID] = Deadlock.Process.value('@ecid', 'int')
  ,-- thread id of given SPID (0 is always the parent)
  [IsolationLevel] = Deadlock.Process.value('@isolationlevel', 'varchar(200)')
  ,[WaitResource] = Deadlock.Process.value('@waitresource', 'varchar(200)')
  ,[LogUsed] = Deadlock.Process.value('@logused', 'int')
 FROM CTE
 CROSS APPLY CTE.DeadlockGraph.nodes('/deadlock-list/deadlock/process-list/process') AS Deadlock(Process)
 )
 ,ExecutionStack
AS (
 -- get the data from the executionStack node
 SELECT CTE.DeadlockID
  ,ProcessID = Execution.Stack.value('../../@id', 'varchar(50)')
  ,Code = Execution.Stack.value('.', 'varchar(1000)')
  ,ProcName = Execution.Stack.value('@procname', 'sysname')
  ,Line = Execution.Stack.value('@line', 'int')
  ,RN = row_number() OVER (
   PARTITION BY CTE.DeadlockID
   ,Execution.Stack.value('../../@id', 'varchar(50)') ORDER BY (
     SELECT 1
     )
   )
 FROM CTE
 CROSS APPLY CTE.DeadlockGraph.nodes('/deadlock-list/deadlock/process-list/process/executionStack/frame') AS Execution(Stack)
 )
 --SELECT * FROM ExecutionStack
 ,PageLock
AS (
 -- get the data from the pagelock node
 SELECT DeadlockID
  ,ObjectName = PageLock.Process.value('../../@objectname', 'varchar(200)')
  ,ProcessID = PageLock.Process.value('@id', 'varchar(200)')
  ,LockType = 'Page'
  ,LockMode = PageLock.Process.value('../../@mode', 'varchar(3)')
 FROM CTE
 CROSS APPLY CTE.DeadlockGraph.nodes('/deadlock-list/deadlock/resource-list/pagelock/owner-list/owner') AS PageLock(Process)
 )
 ,KeyLock
AS (
 -- get the data from the keylock node
 SELECT DeadlockID
  ,ObjectName = KeyLock.Process.value('../../@objectname', 'varchar(200)') + '.' + KeyLock.Process.value('../../@indexname', 'varchar(200)')
  ,-- get the index name also
  ProcessID = KeyLock.Process.value('@id', 'varchar(200)')
  ,LockType = 'Key'
  ,LockMode = KeyLock.Process.value('../../@mode', 'varchar(3)')
 FROM CTE
 CROSS APPLY CTE.DeadlockGraph.nodes('/deadlock-list/deadlock/resource-list/keylock/owner-list/owner') AS KeyLock(Process)
 )
 ,RidLock
AS (
 -- get the data from the ridlock node
 SELECT DeadlockID
  ,ObjectName = RIDLock.Process.value('../../@objectname', 'varchar(200)')
  ,ProcessID = RIDLock.Process.value('@id', 'varchar(200)')
  ,LockType = 'RID'
  ,LockMode = RIDLock.Process.value('../../@mode', 'varchar(3)')
 FROM CTE
 CROSS APPLY CTE.DeadlockGraph.nodes('/deadlock-list/deadlock/resource-list/ridlock/owner-list/owner') AS RIDLock(Process)
 )
 ,ObjectLock
AS (
 -- get the data from the objectlock node
 SELECT DeadlockID
  ,ObjectName = ObjectLock.Process.value('../../@objectname', 'varchar(200)')
  ,ProcessID = ObjectLock.Process.value('@id', 'varchar(200)')
  ,LockType = 'Object'
  ,LockMode = ObjectLock.Process.value('../../@mode', 'varchar(3)')
 FROM CTE
 CROSS APPLY CTE.DeadlockGraph.nodes('/deadlock-list/deadlock/resource-list/objectlock/owner-list/owner') AS ObjectLock(Process)
 )
-- combine all the data together, and display in
SELECT Process.[DeadlockID]
 ,Process.[SPID]
 ,Process.[SBID]
 ,Process.[ECID]
 ,Process.[DeadlockGraph]
 ,-- include the graph - can click and open in separate window
 Process.[ProcessID]
 ,Process.[Victim]
 ,[LockedType] = coalesce(PageLock.LockType, KeyLock.LockType, RIDLock.LockType, ObjectLock.LockType)
 ,[LockMode] = coalesce(PageLock.LockMode, KeyLock.LockMode, RIDLock.LockMode, ObjectLock.LockMode)
 ,[LockedObject] = coalesce(PageLock.ObjectName, KeyLock.ObjectName, RIDLock.ObjectName, ObjectLock.ObjectName)
 ,[Procedure #] = es.RN
 ,es.[ProcName]
 ,es.[Line]
 ,es.[Code]
 ,Process.[ClientApp]
 ,Process.[HostName]
 ,Process.[LoginName]
 ,Process.[TransactionTime]
 ,Process.BatchStarted
 ,Process.BatchCompleted
 ,Process.[InputBuffer]
 ,Process.[IsolationLevel]
 ,Process.WaitResource
 ,Process.LogUsed
FROM Process
INNER JOIN ExecutionStack es ON es.ProcessID = Process.ProcessID
 AND es.DeadlockID = Process.DeadlockID
LEFT JOIN PageLock ON PageLock.ProcessID = Process.ProcessID
 AND PageLock.DeadlockID = Process.DeadlockID
LEFT JOIN KeyLock ON KeyLock.ProcessID = Process.ProcessID
 AND KeyLock.DeadlockID = Process.DeadlockID
LEFT JOIN RIDLock ON RIDLock.ProcessID = Process.ProcessID
 AND RIDLock.DeadlockID = Process.DeadlockID
LEFT JOIN ObjectLock ON ObjectLock.ProcessID = Process.ProcessID
 AND ObjectLock.DeadlockID = Process.DeadlockID
ORDER BY Process.DeadlockID
 ,Process.victim DESC
 ,-- show the victim first
 Process.ProcessID
 ,Process.ECID
 ,-- show in thread order by SPID
 es.RN;-- execution stack order

No comments:

Post a Comment