Understanding and detecting deadlocks in Sql Server

In order to understand deadlocks, let us first create tables and have some sample data.

/* Tables and data  - Start */
IF OBJECT_ID('Order') IS NOT NULL
BEGIN
DROP TABLE [Order]
END

IF OBJECT_ID('Customer') IS NOT NULL
BEGIN
DROP TABLE Customer
END

CREATE TABLE Customer
(
ID int IDENTITY(1,1) CONSTRAINT PK_cid PRIMARY KEY ,
Name varchar(20)
)

CREATE TABLE [Order]
(
ID int IDENTITY(1,1) CONSTRAINT PK_oid PRIMARY KEY ,
CustomerId int,
OrderDate datetime
)

ALTER TABLE [Order]
ADD FOREIGN KEY (CustomerID)
REFERENCES Customer(ID)

INSERT INTO Customer (Name)
SELECT 'xxx'
UNION ALL
SELECT 'yyy'
UNION ALL
SELECT 'zzz'

INSERT INTO [Order] (CustomerID, OrderDate)
SELECT 1, GetDate()
UNION ALL
SELECT 2, GetDate()
UNION ALL
SELECT 3, GetDate()
/* Tables and data  - End*/

Open Sql Profiler and use the “TSQL_Locks” template.

image

In the “Event selection” tab, make sure you have “Deadlock Graph” selected and the click “Run”.

image

In SSMS, open two new query windows and execute the below batches in those two separate windows at the same time (Hit F5 in one window, switch to the another and hit F5).

Batch 1

/*Transaction A updates record A in table A - Waits and then updates record B in table B*/
BEGIN TRANSACTION
UPDATE Customer SET Name = 'aaa' WHERE ID=1
WAITFOR DELAY '00:00:10' -- Waiting for 10 secs
UPDATE [Order] SET CustomerId = 1 WHERE ID = 2
COMMIT TRANSACTION

Batch 2

/*Transaction B updates record B in table B - Waits and then updates the updates record A in table A */
-- This causes deadlock
BEGIN TRANSACTION
UPDATE [Order] SET OrderDate = GetDate() WHERE Id = 2
WAITFOR DELAY '00:00:10' -- Waiting for 10 secs
UPDATE Customer SET Name = 'bbb' WHERE Id=1
COMMIT TRANSACTION

You will notice that the batch 1 transaction took affect but because batch 2 couldn’t as that was identified as deadlock victim.

image

Look at the profiler now.

image

Notice that the Batch 2 didn’t get committed (See the big blue cross on the left circle and the tool tip on it in the above screenshot from the profiler?). However the Batch 1 did go through and took effect (see below).

image

Note that If the above batches (separate transactions) were updating two different records at the same time, there wont be any deadlocks.

/* Transaction A updates record A in table A waits and the updates record B in table B*/
BEGIN TRANSACTION
UPDATE Customer SET Name = 'aaa' WHERE ID=2
PRINT 'Customer updated...'
WAITFOR DELAY '00:00:10' -- Waiting for 10 secs
UPDATE [Order] SET CustomerId = 1 WHERE ID = 2
PRINT 'Order updated...'
COMMIT TRANSACTION

/*  Should be executed on a separate query window
Transaction B updates record C in table A waits and the updates record C in table B */
BEGIN TRANSACTION
UPDATE [Order] SET OrderDate = GetDate() WHERE Id = 3
PRINT 'Order updated'
WAITFOR DELAY '00:00:10' -- Waiting for 5 secs
UPDATE Customer SET Name = 'bbb' WHERE Id=3
PRINT 'Customer updated'
COMMIT TRANSACTION

image

Advertisements

,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Random Thoughts

The World as I see it

Simple Programmer

Making The Complex Simple

Ionic Solutions

Random thoughts on software construction, design patterns and optimization.

Long (Way) Off

A tragic's view from the cricket hinterlands

%d bloggers like this: