[MSSQL] 如何從ErrorLog分析Deadlock

  • 928
  • 0
  • 2015-09-04

必須開啟Trace Flags 1222才會寫ErrorLog, 此外, Deadlock必須返回錯誤, 才會寫ErrorLog, 但一般若沒設Deadlock Priority或Timeout, Process們會互咬不放, 根本不會返回錯誤

1. 限制:

必須開啟Trace Flags 1222才會寫ErrorLog, 可配合sp_cycle_errorlog產生新的ErrorLog

Deadlock必須返回錯誤, 才會寫ErrorLog, 但一般若沒設Deadlock Priority或Timeout, Process們會互咬不放, 根本不會返回錯誤

sp_cycle_errorlog
DBCC TRACEON (1222,-1)

 

2. 模擬Deadlock 

--Session1
SET DEADLOCK_PRIORITY HIGH
BEGIN TRAN
	UPDATE LinkedUUTQSMC SET Work_Order='201162848-1' WHERE SN='1050QCQ06B'
	WAITFOR DELAY '00:01' 
	UPDATE LinkedUUTQSMC SET Work_Order='201162848-1' WHERE SN='QTFCQK14240099'
COMMIT TRAN

 

--Session2
BEGIN TRAN
	UPDATE LinkedUUTQSMC SET Work_Order='201162848-1' WHERE SN='QTFCQK14240099'
	UPDATE LinkedUUTQSMC SET Work_Order='201162848-1' WHERE SN='1050QCQ06B'
COMMIT TRAN

 

3. 取得ErrorLog

SQL Server 2012的ErrorLog位於C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Log\ERRORLOG

 

4. 分析ErrorLog

 

5. 找出被鎖定的table, index, value

--1. 找出objectname=CompData.dbo.LinkedUUTQSMC
--2. 找出hobtid=72057594039500800, associatedObjectId=72057594039500800
--3. 找出waitresource=KEY:6:72057594039500800(22c1ba5a1cc7)

--4. 用table找出被鎖定的index : PK_LinkedUUTQSMC
SELECT [index]=name, [type]=type_desc FROM sys.indexes WHERE object_id=object_id('CompData.dbo.LinkedUUTQSMC')

--5. 用hobtid或associatedObjectId找出被鎖定的table,index : LinkedUUTQSMC, PK_LinkedUUTQSMC
SELECT [table]=OBJECT_NAME(i.object_id), [index]=i.name FROM sys.partitions p, sys.indexes i WHERE i.object_id=p.object_id AND i.index_id=p.index_id AND p.partition_id=72057594039500800

--6. 用table,index,lockres找出被鎖定的value: 1050QCQ06B
SELECT lockres=%%lockres%%, CompData.dbo.LinkedUUTQSMC.* FROM CompData.dbo.LinkedUUTQSMC WITH(INDEX(PK_LinkedUUTQSMC)) WHERE %%lockres%% ='(22c1ba5a1cc7)'

--7. 用table,index,value找出被鎖定的page : (1:505800:0)
SELECT physloc=%%physloc%%,[page]=sys.fn_physlocformatter(%%physloc%%),CompData.dbo.LinkedUUTQSMC.* FROM CompData.dbo.LinkedUUTQSMC WITH(INDEX(PK_LinkedUUTQSMC)) WHERE SN='1050QCQ06B'  
 
--8. 印出page詳細資訊
DBCC TRACEON(3604)
DBCC PAGE (6,1,505800,1) --DBCC PAGE (dbid,fileid,pageid,1)

 

6. 程式化分析ErrorLog

CREATE FUNCTION [dbo].[ufn_ErrorLogToTable](
    @Text VARCHAR(8000), 
	@FieldTerminator VARCHAR(8000),
	@RowTerminator VARCHAR(8000)
) RETURNS @Table TABLE (Stmt VARCHAR(8000))

BEGIN

DECLARE @FieldTerminatorPosition INT
DECLARE @RowTerminatorPosition INT
DECLARE @Item VARCHAR(8000)=''
DECLARE @Value VARCHAR(8000)=''

--單引號'
IF CHARINDEX('''',@Text)<>0 
BEGIN
	INSERT @Table SELECT @Text
	RETURN
END

--@
IF CHARINDEX('@',@Text)<>0 
BEGIN
	INSERT @Table SELECT @Text
	RETURN
END

--沒有=
IF CHARINDEX(@FieldTerminator,@Text)=0
BEGIN
	INSERT @Table SELECT @Text
	RETURN
END

--特殊字元
SET @Text=REPLACE(@Text, ': ',':')
SET @Text=REPLACE(@Text, ' (','(')

--有=
WHILE CHARINDEX(@FieldTerminator,@Text)<>0
BEGIN	
	SET @FieldTerminatorPosition=CHARINDEX(@FieldTerminator,@Text)
	SET @RowTerminatorPosition=CHARINDEX(@RowTerminator,@Text,@FieldTerminatorPosition)
	IF @RowTerminatorPosition=0 SET @RowTerminatorPosition=LEN(@Text)
	SET @Item=RTRIM(LTRIM(SUBSTRING(@Text,1,@FieldTerminatorPosition-1)))
	SET @Value=RTRIM(LTRIM(SUBSTRING(@Text,@FieldTerminatorPosition+1,@RowTerminatorPosition-@FieldTerminatorPosition)))
	IF @RowTerminatorPosition>0 SET @Text=RIGHT(@Text,LEN(@Text)-@RowTerminatorPosition)
	INSERT @Table SELECT @Item+@FieldTerminator+@Value
END

RETURN
END

 

DECLARE @ErrorLogFile NVARCHAR(100)='C:\Users\99050301\Desktop\ERRORLOG'
DEClARE	@Cmd NVARCHAR(MAX)=''

--ErrorLog
IF OBJECT_ID('ErrorLog') IS NOT NULL DROP TABLE ErrorLog
CREATE TABLE ErrorLog (Text VARCHAR(MAX))
SET @Cmd=N'BULK INSERT ErrorLog FROM '+ QUOTENAME(@ErrorLogFile, '''') +' WITH (BATCHSIZE=1000,FIRSTROW=1,ROWTERMINATOR=''\n'',TABLOCK)'
EXEC(@Cmd)

--Deadlock
DECLARE @ErrorLog TABLE (ErrorLogRow INT IDENTITY(1,1), ErrorLogDateTime VARCHAR(50), ErrorLogSpid VARCHAR(50), ErrorLogText VARCHAR(MAX))
INSERT @ErrorLog (ErrorLogDateTime, ErrorLogSpid, ErrorLogText) SELECT LEFT(Text,22), SUBSTRING(Text,23,7), CASE WHEN LEN(Text)>30 THEN LTRIM(RIGHT(Text,LEN(Text)-30)) ELSE Text END FROM ErrorLog 

--DeadlockStmt
DECLARE @ErrorLogRow INT
DECLARE @ErrorLogDateTime VARCHAR(50)
DECLARE @ErrorLogSpid VARCHAR(50)
DECLARE @ErrorLogText VARCHAR(MAX)
DECLARE @ErrorLogStmt TABLE (ErrorLogRow INT, ErrorLogDateTime VARCHAR(50), ErrorLogSpid VARCHAR(50), DeadlockCategory VARCHAR(MAX), ErrorLogStmt VARCHAR(MAX), ErrorLogText VARCHAR(MAX))
DECLARE DeadlockCur CURSOR FOR SELECT ErrorLogRow, ErrorLogDateTime, ErrorLogSpid, ErrorLogText FROM @ErrorLog
OPEN DeadlockCur FETCH NEXT FROM DeadlockCur INTO @ErrorLogRow, @ErrorLogDateTime, @ErrorLogSpid, @ErrorLogText
WHILE @@FETCH_STATUS=0
BEGIN
	INSERT @ErrorLogStmt (ErrorLogRow, ErrorLogDateTime, ErrorLogSpid, DeadlockCategory, ErrorLogStmt, ErrorLogText)
	SELECT @ErrorLogRow, @ErrorLogDateTime, @ErrorLogSpid, '', Stmt, @ErrorLogText 
	FROM [dbo].[ufn_ErrorLogToTable] (@ErrorLogText,'=',' ') 
    FETCH NEXT FROM DeadlockCur INTO @ErrorLogRow, @ErrorLogDateTime, @ErrorLogSpid, @ErrorLogText
END 
CLOSE DeadlockCur;
DEALLOCATE DeadlockCur;

--DeadlockCategory
UPDATE D1 SET DeadlockCategory='deadlock-list: '+D2.ErrorLogDateTime FROM @ErrorLogStmt D1, (SELECT * FROM @ErrorLogStmt WHERE ErrorLogStmt='deadlock-list') D2 WHERE D1.ErrorLogDateTime=D2.ErrorLogDateTime AND D1.ErrorLogRow=D2.ErrorLogRow
UPDATE D1 SET DeadlockCategory=REPLACE(D2.ErrorLogStmt,'process id=','process-list: ') FROM @ErrorLogStmt D1, (SELECT * FROM @ErrorLogStmt WHERE ErrorLogStmt LIKE 'process id%') D2 WHERE D1.ErrorLogDateTime=D2.ErrorLogDateTime AND D1.ErrorLogStmt=D2.ErrorLogStmt
UPDATE D1 SET DeadlockCategory=REPLACE(D2.ErrorLogStmt,'objectname=','resource-list: ') FROM @ErrorLogStmt D1, (SELECT * FROM @ErrorLogStmt WHERE ErrorLogStmt LIKE 'objectname%') D2 WHERE D1.ErrorLogDateTime=D2.ErrorLogDateTime AND D1.ErrorLogStmt=D2.ErrorLogStmt
UPDATE D1 SET DeadlockCategory=REPLACE(D2.ErrorLogStmt,'owner id=','owner-list: ') FROM @ErrorLogStmt D1, (SELECT * FROM @ErrorLogStmt WHERE ErrorLogStmt LIKE 'owner id%') D2 WHERE D1.ErrorLogDateTime=D2.ErrorLogDateTime AND D1.ErrorLogStmt=D2.ErrorLogStmt
UPDATE D1 SET DeadlockCategory=REPLACE(D2.ErrorLogStmt,'waiter id=','waiter-list: ') FROM @ErrorLogStmt D1, (SELECT * FROM @ErrorLogStmt WHERE ErrorLogStmt LIKE 'waiter id%') D2 WHERE D1.ErrorLogDateTime=D2.ErrorLogDateTime AND D1.ErrorLogStmt=D2.ErrorLogStmt

SELECT * FROM @ErrorLogStmt WHERE ErrorLogRow BETWEEN 14 AND 53 ORDER BY ErrorLogRow