Demo Preparation
1
2Create Database [Deadlockdemo]
3go
4use [Deadlockdemo];
5go
6CREATE TABLE dbo.invoices_demo (
7 id int NOT NULL,
8 num nvarchar(20) NOT NULL,
9 customer nvarchar(100) NOT NULL,
10 created_at DateTime NOT NULL,
11 updated_at DateTime NOT NULL,
12 CONSTRAINT PK_invoices PRIMARY KEY (id)
13);
14
15CREATE TABLE dbo.invoice_items_demo (
16 invoice_id int NOT NULL,
17 item_index int NOT NULL,
18 product nvarchar(100) NOT NULL,
19 qty int NOT NULL,
20 price money NOT NULL,
21 CONSTRAINT PK_invoice_items PRIMARY KEY (invoice_id, item_index)
22);
23
24INSERT INTO dbo.invoices_demo (id, num, customer, created_at, updated_at) VALUES
25(1, 'INV180125', 'NASA', '2018-01-25', '2018-01-25'),
26(2, 'INV180128', 'SpaceX', '2018-01-28', '2018-01-28');
27INSERT INTO invoice_items_demo (invoice_id, item_index, product, qty, price) VALUES
28(1, 1, 'NK-33 engine', 7, 145000),
29(1, 2, 'Rocketdyne RS-25', 2, 560000),
30(2, 1, 'Merlin 1D engine', 7, 125000),
31(2, 2, 'J58 engine', 3, 225000);
32GO
33
34-- Database Configuration
35DBCC TRACEON (1204, 1222)
36DBCC TRACESTATUS (1204, 1222)
37EXEC sp_altermessage 1205, 'WITH_LOG', 'true'
38GO
39
40-- Extended Event Implementation
41CREATE EVENT SESSION [blocked_process] ON SERVER
42ADD EVENT sqlserver.blocked_process_report(
43 ACTION(sqlserver.client_app_name,
44 sqlserver.client_hostname,
45 sqlserver.database_name)) ,
46ADD EVENT sqlserver.xml_deadlock_report (
47 ACTION(sqlserver.client_app_name,
48 sqlserver.client_hostname,
49 sqlserver.database_name,sqlserver.sql_text))
50ADD TARGET package0.asynchronous_file_target
51(SET filename = N'C:\temp\blocked_process.xel', -- maybe, you need to change the path location
52 metadatafile = N'C:\temp\blocked_process.xem',
53 max_file_size=(65536),
54 max_rollover_files=5)
55WITH (MAX_DISPATCH_LATENCY = 5SECONDS)
56GO
57
58-- Enable the Blocked Process Threshold
59EXEC sp_configure 'show advanced options', 1 ;
60GO
61RECONFIGURE ;
62GO
63EXEC sp_configure 'blocked process threshold', '5';
64RECONFIGURE
65GO
66
67-- Enable the Extended Event
68ALTER EVENT SESSION [blocked_process] ON SERVER
69STATE = START;
70GO
SQL Server Custom Jobs Implementation
1
2-- Create table on MSDB Database
3USE MSDB
4GO
5SET ANSI_NULLS ON
6GO
7SET QUOTED_IDENTIFIER ON
8GO
9CREATE TABLE [dbo].[Blocking](
10 [ID] [bigint] IDENTITY(1,1) NOT NULL,
11 [ProcessWaiting] [varchar](1000) NULL,
12 [ProcessBlocking] [varchar](1000) NULL,
13 [WaitingQuery] [nvarchar](4000) NULL,
14 [blockingQuery] [nvarchar](4000) NULL,
15 [astatus] [varchar](1000) NULL,
16 [bstatus] [varchar](1000) NULL,
17 [waittime] [varchar](1000) NULL,
18 [killbill] [varchar](1000) NULL,
19 [Instance] [varchar](1000) NULL,
20 [DBName] [varchar](1000) NULL,
21 [Btime] [datetime] NULL
22) ON [PRIMARY]
23GO
24
25ALTER TABLE [dbo].[Blocking] ADD CONSTRAINT [DF_Blocking_Btime] DEFAULT (getdate()) FOR [Btime]
26GO
Monitoring the deadlock live
1SELECT a.spid ProcessWaiting
2 ,a.blocked ProcessBlocking
3 ,sptxt.TEXT WaitingQuery
4 ,blktxt.TEXT blockingQuery
5 ,a.STATUS
6 ,b.STATUS
7 ,a.waittime
8 ,convert(varchar,dateadd(ms,a.waittime,0),114) as [waittime hms]
9 ,@@SERVERNAME AS ServerName
10 ,db_name(a.dbid) AS DBName
11 ,'KILL ' + cast(a.blocked AS VARCHAR) KILLBill
12FROM sys.sysprocesses a
13CROSS APPLY sys.dm_exec_sql_text(a.sql_handle) sptxt
14JOIN sys.sysprocesses b ON a.blocked = b.spid
15CROSS APPLY sys.dm_exec_sql_text(b.sql_handle) blktxt
16WHERE a.blocked <> 0
17ORDER BY a.spid
Create Job Capture_Blocking
1
2USE [msdb]
3GO
4BEGIN TRANSACTION
5DECLARE @ReturnCode INT
6SELECT @ReturnCode = 0
7
8IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
9BEGIN
10EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
11IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
12
13END
14DECLARE @jobId BINARY(16)
15EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'Capture_Blocking',
16 @enabled=1,
17 @notify_level_eventlog=0,
18 @notify_level_email=0,
19 @notify_level_netsend=0,
20 @notify_level_page=0,
21 @delete_level=0,
22 @description=N'No description available.',
23 @category_name=N'[Uncategorized (Local)]', @job_id = @jobId OUTPUT
24IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
25
26EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Blocking',
27 @step_id=1,
28 @cmdexec_success_code=0,
29 @on_success_action=1,
30 @on_success_step_id=0,
31 @on_fail_action=3,
32 @on_fail_step_id=0,
33 @retry_attempts=0,
34 @retry_interval=0,
35 @os_run_priority=0, @subsystem=N'TSQL',
36 @command=N'
37USE [msdb]
38GO
39INSERT INTO [dbo].[Blocking]
40 ([ProcessWaiting]
41 ,[ProcessBlocking]
42 ,[WaitingQuery]
43 ,[blockingQuery]
44 ,[astatus]
45 ,[bstatus]
46 ,[waittime]
47 ,[Instance]
48 ,[DBName]
49 ,[killbill]
50 )
51
52 select a.spid ProcessWaiting,a.blocked ProcessBlocking,sptxt.text WaitingQuery, blktxt.text blockingQuery
53,a.status,b.status , a.waittime , @@SERVERNAME as ServerName , db_name(a.dbid) as DBName
54,''KILL '' + cast(a.blocked as varchar) KILLBill
55from sys.sysprocesses
56a cross apply sys.dm_exec_sql_text(a.sql_handle) sptxt
57join sys.sysprocesses b on a.blocked = b.spid
58cross apply sys.dm_exec_sql_text(b.sql_handle) blktxt
59where a.blocked <> 0
60order by a.spid
61',
62 @database_name=N'msdb',
63 @flags=0
64IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
65EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
66IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
67EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Blocking_Schdule1',
68 @enabled=1,
69 @freq_type=4,
70 @freq_interval=1,
71 @freq_subday_type=2,
72 @freq_subday_interval=10,
73 @freq_relative_interval=0,
74 @freq_recurrence_factor=0,
75 @active_start_date=20201108,
76 @active_end_date=99991231,
77 @active_start_time=0,
78 @active_end_time=235959,
79 @schedule_uid=N'31cdc500-1447-4926-97af-62073fc8fff0'
80IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
81EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
82IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
83COMMIT TRANSACTION
84GOTO EndSave
85QuitWithRollback:
86 IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
87EndSave:
88GO
Deadlock Simulation
Open SQL Server session and execute :
1
2Print '-- Deadlock simulation Session 1'
3USE Deadlockdemo;
4GO
5BEGIN TRANSACTION
6 UPDATE invoices_demo SET updated_at = GETDATE() WHERE id = 1;
7 WAITFOR DELAY '00:00:10'; -- 10s
8 UPDATE invoice_items_demo SET qty = qty + 1 WHERE invoice_id = 1 AND item_index = 2;
9ROLLBACK TRANSACTION
Open the second SQL Server session and execute :
1
2Print '-- Deadlock simulation Session 2'
3USE Deadlockdemo;
4GO
5BEGIN TRANSACTION
6 UPDATE invoice_items_demo SET qty = qty + 1 WHERE invoice_id = 1 AND item_index = 2;
7 WAITFOR DELAY '00:00:10';
8 UPDATE invoices_demo SET updated_at = GETDATE() WHERE id = 1;
9ROLLBACK TRANSACTION
Capture the Deadlock information using SQL Server Error Log
1
2--Create Temporary table on Tempdb Database
3Create table #Logs
4(Logdate Datetime, Processinfo Varchar(100), Errortext Varchar(4000))
5GO
6---Load the SQL Server Error Log on temp table #Log
7insert into #Logs
8EXEC master.dbo.xp_readerrorlog
9GO
10--Select the Deadlock errors
11Select * from #Logs
12where Errortext like '%Deadlock%'
13order by Logdate DESC
14--Drop the #Log table
15GO
16Drop table #Logs
Capture the Deadlock information using SQL Server Extended Event
1
2WITH events_cte AS (
3 SELECT
4 xevents.event_data,
5 DATEADD(mi,
6 DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP),
7 xevents.event_data.value(
8 '(event/@timestamp)[1]', 'datetime2')) AS [event time] ,
9 xevents.event_data.value(
10 '(event/action[@name="client_app_name"]/value)[1]', 'nvarchar(128)')
11 AS [client app name],
12 xevents.event_data.value(
13 '(event/action[@name="client_hostname"]/value)[1]', 'nvarchar(max)')
14 AS [client host name],
15 xevents.event_data.value(
16 '(event[@name="blocked_process_report"]/data[@name="database_name"]/value)[1]', 'nvarchar(max)')
17 AS [database name],
18 xevents.event_data.value(
19 '(event[@name="blocked_process_report"]/data[@name="database_id"]/value)[1]', 'int')
20 AS [database_id],
21 xevents.event_data.value(
22 '(event[@name="blocked_process_report"]/data[@name="object_id"]/value)[1]', 'int')
23 AS [object_id],
24 xevents.event_data.value(
25 '(event[@name="blocked_process_report"]/data[@name="index_id"]/value)[1]', 'int')
26 AS [index_id],
27 xevents.event_data.value(
28 '(event[@name="blocked_process_report"]/data[@name="duration"]/value)[1]', 'bigint') / 1000
29 AS [duration (ms)],
30 xevents.event_data.value(
31 '(event[@name="blocked_process_report"]/data[@name="lock_mode"]/text)[1]', 'varchar')
32 AS [lock_mode],
33 xevents.event_data.value(
34 '(event[@name="blocked_process_report"]/data[@name="login_sid"]/value)[1]', 'int')
35 AS [login_sid],
36 xevents.event_data.query(
37 '(event[@name="blocked_process_report"]/data[@name="blocked_process"]/value/blocked-process-report)[1]')
38 AS blocked_process_report,
39 xevents.event_data.query(
40 '(event/data[@name="xml_report"]/value/deadlock)[1]')
41 AS deadlock_graph
42 FROM sys.fn_xe_file_target_read_file
43 ('C:\temp\blocked_process*.xel',
44 'C:\temp\blocked_process*.xem',
45 null, null)
46 CROSS APPLY (SELECT CAST(event_data AS XML) AS event_data) as xevents
47)
48SELECT
49 CASE WHEN blocked_process_report.value('(blocked-process-report[@monitorLoop])[1]', 'nvarchar(max)') IS NULL
50 THEN 'Deadlock'
51 ELSE 'Blocked Process'
52 END AS ReportType,
53 [event time],
54 CASE [client app name] WHEN '' THEN ' -- N/A -- '
55 ELSE [client app name]
56 END AS [client app _name],
57 CASE [client host name] WHEN '' THEN ' -- N/A -- '
58 ELSE [client host name]
59 END AS [client host name],
60 [database name],
61 COALESCE(OBJECT_SCHEMA_NAME(object_id, database_id), ' -- N/A -- ') AS [schema],
62 COALESCE(OBJECT_NAME(object_id, database_id), ' -- N/A -- ') AS [table],
63 index_id,
64 [duration (ms)],
65 lock_mode,
66 COALESCE(SUSER_NAME(login_sid), ' -- N/A -- ') AS username,
67 CASE WHEN blocked_process_report.value('(blocked-process-report[@monitorLoop])[1]', 'nvarchar(max)') IS NULL
68 THEN deadlock_graph
69 ELSE blocked_process_report
70 END AS Report
71FROM events_cte
72ORDER BY [event time] DESC
Capture the Deadlock information using the System_Health Default Extended Event
- You must look for where the files are:
1C:\>dir system_health* /s /b
1
2SELECT s.name, se.event_name
3FROM sys.dm_xe_sessions s
4 INNER JOIN sys.dm_xe_session_events se ON (s.address = se.event_session_address) and (event_name = 'xml_deadlock_report')
5WHERE name = 'system_health'
6SELECT CONVERT(xml, event_data).query('/event/data/value/child::*'),
7 CONVERT(xml, event_data).value('(event[@name="xml_deadlock_report"]/@timestamp)[1]','datetime') as Execution_Time
8FROM sys.fn_xe_file_target_read_file('C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Log\system_health*.xel', null, null, null)
9WHERE object_name like 'xml_deadlock_report'
Capture the Deadlock counts per Day
1SELECT
2 'Deadlocks Occurrences Report',
3 CONVERT(BIGINT,((1.0 * p.cntr_value /
4NULLIF(datediff(DD,d.create_date,CURRENT_TIMESTAMP),0)))) as
5AveragePerDay,
6 CAST(p.cntr_value AS NVARCHAR(100)) + ' deadlocks have been recorded
7since startup.' AS Details,
8 d.create_date as StartupDateTime
9FROM sys.dm_os_performance_counters p
10INNER JOIN sys.databases d ON d.name = 'tempdb'
11WHERE RTRIM(p.counter_name) = 'Number of Deadlocks/sec'
12AND RTRIM(p.instance_name) = '_Total'
13;
Capture the Deadlock information using SQL Server Custom Jobs
1
2Select * from MSDB..Blocking
3order by Btime DESC
Source: []:(https://www.brentozar.com/archive/2014/03/extended-events-doesnt-hard/) []:(https://mostafaelmasry.com/2020/11/08/monitoring-and-tracking-sql-server-deadlock-process/)
Comments