patternsqlModerate
Good reasons to use SELECT... WITH XLOCK?
Viewed 0 times
withxlockreasonsgoodselectuse
Problem
I am facing some re-occurring deadlocks, one of which is a Keylock and contains a SELECT query with XLOCK hint that becomes the deadlock victim. The other statement is an INSERT into one of the tables that is part of the view of the first query.
View:
Select Query:
INSERT Statement:
The underlying table dbo.E is holding about 3 million rows in about 20 columns, some of them are ntext.
Taking the queries out and simulating it manually with two transactions, the behaviour is re-producable. The behaviour changes if XLOCK is removed from the select.
Deadlock Graph:
As far I understand this, I am looking at a KEYLOCK deadlock basically caused by an uncovered index query that uses a nonclustered and a clustered index in order to collect the required values, right?
My questions:
View:
create view dbo.viewE
as
select * from dbo.E
where myValue > 13000Select Query:
select * from dbo.viewE with (XLOCK) where A > GETUTCDATE()INSERT Statement:
INSERT INTO [dbo].[E] (myValue,A) VALUES (10,GetDate())The underlying table dbo.E is holding about 3 million rows in about 20 columns, some of them are ntext.
Taking the queries out and simulating it manually with two transactions, the behaviour is re-producable. The behaviour changes if XLOCK is removed from the select.
Deadlock Graph:
SELECT * FROM viewE WITH (XLOCK) WHERE A < GetUtcDate()
unknown
(@UICulture nvarchar(5))SELECT * FROM viewE WITH (XLOCK) WHERE A < GetUtcDate()
INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
unknown
INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
As far I understand this, I am looking at a KEYLOCK deadlock basically caused by an uncovered index query that uses a nonclustered and a clustered index in order to collect the required values, right?
My questions:
- I can't create a covering index because of the required NTEXT columns involved. Will drastically reducing the number of rows help here?
- Is there any good reason I just don't know the SELECT is executed with the XLOCK? Would the deadlock also happen without XLOCK?
Solution
As far I understand this, I am looking at a KEYLOCK deadlock basically caused by an uncovered index query that uses a nonclustered and a clustered index in order to collect the required values, right?
Essentially, yes. The read operation (select) accesses the nonclustered index first, then the clustered index (lookup). The write operation (insert) accesses the clustered index first, then the nonclustered index. Accessing the same resources in a different order holding incompatible locks can lead to deadlock.
Will drastically reducing the number of rows help here?
It might, because fewer resources are locked and the operation will tend to complete more quickly. If it does help, it may reduce deadlocks, but most likely not eliminate them (but read on).
Is there any good reason I just don't know the SELECT is executed with the XLOCK?
Not really. Locking hints like this are often introduced by people without a full understanding of how isolation, locking, and deadlocks work, in a desperate attempt to reduce or eliminate a problem.
Would the deadlock also happen without XLOCK?
No, if the select actually runs at read uncommitted isolation because incompatible locks won't be taken (and held) in a different order.
Yes, if a locking isolation level is used, and incompatible locks are taken and held in an inconsistent order, for example shared (S) on the nonclustered, then S on the clustered when reading. How likely a deadlock is in this scenario depends on how many locks are taken, and for how long they are held.
Advice
The thing that really stands out (on review) is that the select transaction is running under serializable isolation. That could be being set by your framework, or due to the use of the DTC (Distributed Transaction Coordinator) - see transactionname="DTCXact" in the deadlock graph. You should look into the reasons for this, and look to change it if possible.
Without this escalation to serializable, the chances are very good that this deadlock would not occur, assuming the
If your application and SQL Server code can tolerate reading versions of rows, changing to read committed snapshot isolation (RCSI) or snapshot isolation (SI) for the reads would also avoid the deadlock (
Ultimately, the
Essentially, yes. The read operation (select) accesses the nonclustered index first, then the clustered index (lookup). The write operation (insert) accesses the clustered index first, then the nonclustered index. Accessing the same resources in a different order holding incompatible locks can lead to deadlock.
Will drastically reducing the number of rows help here?
It might, because fewer resources are locked and the operation will tend to complete more quickly. If it does help, it may reduce deadlocks, but most likely not eliminate them (but read on).
Is there any good reason I just don't know the SELECT is executed with the XLOCK?
Not really. Locking hints like this are often introduced by people without a full understanding of how isolation, locking, and deadlocks work, in a desperate attempt to reduce or eliminate a problem.
Would the deadlock also happen without XLOCK?
No, if the select actually runs at read uncommitted isolation because incompatible locks won't be taken (and held) in a different order.
Yes, if a locking isolation level is used, and incompatible locks are taken and held in an inconsistent order, for example shared (S) on the nonclustered, then S on the clustered when reading. How likely a deadlock is in this scenario depends on how many locks are taken, and for how long they are held.
Advice
The thing that really stands out (on review) is that the select transaction is running under serializable isolation. That could be being set by your framework, or due to the use of the DTC (Distributed Transaction Coordinator) - see transactionname="DTCXact" in the deadlock graph. You should look into the reasons for this, and look to change it if possible.
Without this escalation to serializable, the chances are very good that this deadlock would not occur, assuming the
XLOCK hint is removed. That said, you would be reading under read uncommitted isolation, which comes with very few consistency guarantees.If your application and SQL Server code can tolerate reading versions of rows, changing to read committed snapshot isolation (RCSI) or snapshot isolation (SI) for the reads would also avoid the deadlock (
XLOCK removed!), while presenting a consistent, point-in-time view of the committed data. This also assumes you can avoid the serializable isolation, of course.Ultimately, the
XLOCK hint is counter-productive, but you really need to look into the reason for the use of the serializable isolation level. The trancount = 2 is also interesting - perhaps you are unintentionally nesting transactions here. Something else to check.Context
StackExchange Database Administrators Q#126885, answer score: 15
Revisions (0)
No revisions yet.