Deadlocks can be a common issue in SQL Server, causing performance problems and impacting the overall stability of the system. In this article, we will discuss how to detect and notify deadlocks in SQL Server.
The Problem
A client recently contacted me because they were experiencing deadlocks in their SQL Server 2005 database. They wanted to be notified via email whenever a deadlock occurred. However, the usual method of using the sp_altermessage
stored procedure was not working in SQL Server 2005.
In SQL Server 2005, you can only run sp_altermessage
against messages with IDs greater than or equal to 50,000. This limitation prevents us from associating a system message with an alert that does not have the WITH_LOG
option specified, resulting in the alert not firing.
The Workaround
To overcome this limitation, I have developed a workaround that utilizes Database Mail and SQL Server Agent. Here are the steps to implement this workaround:
- Make sure Database Mail is configured in your SQL Server instance.
- Ensure that SQL Server Agent has the correct Alert System Configurations set to utilize this method.
- Enable Traceflag 1222 by running the command
DBCC TRACEON(1222, -1)
. - Create a stored procedure that performs the following steps:
IF OBJECT_ID('dbo.usp_DeadlockNotification') IS NOT NULL
DROP PROC dbo.usp_DeadlockNotification
CREATE PROC dbo.usp_DeadlockNotification
@FilterBIT = 0,
@Minutes INT = 30
AS
DECLARE @ErrorLog TABLE
(
LogDate DATETIME NOT NULL,
ProcessInfo VARCHAR(75),
LogInfo VARCHAR(MAX)
)
DECLARE @Count INT,
@StartDate DATETIME,
@EndDate DATETIME
SET @Count = 0
SET NOCOUNT ON
-- Step I: Import Errorlog
INSERT INTO @Errorlog
EXEC xp_readerrorlog
-- Step II: How to search Errorlog
IF (@Filter <> 0)
BEGIN
SELECT @EndDate = GETDATE()
SELECT @StartDate = DATEADD(mi, -@Minutes, @EndDate)
SELECT @Count = COUNT(*)
FROM @Errorlog
WHERE LogDate BETWEEN @StartDate AND @EndDate
AND LogInfo LIKE '%Deadlock%'
END
ELSE
BEGIN
SELECT @Count = COUNT(*)
FROM @Errorlog
WHERE LogInfo LIKE '%Deadlock%'
END
-- Step III: Send Email
IF (@Count > 0)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'SQLTestCluster',
@recipients = 'pleblanc@lamar.com',
@subject = 'Deadlocks',
@body = 'Please check errorlog for Deadlocks'
END
Once you have created the stored procedure, create a SQL Job that runs at intervals during the day when you suspect deadlocks may occur. Add a step to the job that executes the stored procedure.
For example:
EXEC dbo.usp_DeadlockNotification 1, 60
Schedule the job to run as needed.
Alternative Method
Another possible method of detecting deadlocks programmatically is to use the sys.dm_os_performance_counters
dynamic management view. This method involves replacing the previous stored procedure with the following:
CREATE PROC dbo.usp_DeadlockNotification
AS
DECLARE @NumOfDeadLocks int
SELECT @NumOfDeadLocks = SUM(cntr_value)
FROM sys.dm_os_performance_counters
WHERE counter_name LIKE '%dead%'
SET NOCOUNT ON
IF (@NumOfDeadLocks > 0)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'SQLTestCluster',
@recipients = 'pleblanc@tsqlscripts.com',
@subject = 'Deadlocks',
@body = 'Please check errorlog for Deadlocks'
END
However, it is important to note that the behavior of the sys.dm_os_performance_counters
dynamic management view is still being researched. The data may be reset or refreshed at certain intervals, which could result in unwanted alerts.
Conclusion
By implementing the workaround described in this article, you can detect and notify deadlocks in your SQL Server database. The client in this example was able to receive notifications every 30 minutes and take appropriate actions to resolve the deadlocks.
If you have any questions, concerns, comments, or suggestions regarding this article, please feel free to email me at pleblanc@tsqlscripts.com.