Wednesday, October 21, 2015

Lock Escalation

Lock Escalations are an optimization technique used by SQL Server to control the amount of locks that are held within the Lock Manager of SQL Server.

Lock hierarchy start in in Order as Database->Table-> Page –Row.

The lock hierarchy starts at the database level, and goes down to the row level. You always have a Shared Lock (S) on the database level itself. When your query is connected to a database (e.g. USE MyDB), the Shared Lock prevents the dropping of the database, or that backups are restored over that database. And underneath the database level, you have locks on the table, on the pages, and the records when you are performing an operation.

In SELECT statement, you have an Intent Shared Lock (IS) on the table and page level, and a Shared Lock (S) on the record itself. In modification statement (INSERT, UPDATE, DELETE), you have an Intent Exclusive or Update Lock (IX or IU) on the table and page level, and a Exclusive or Update Lock (X or U) on the changed records. SQL Server always acquires locks from top to bottom to prevent so-called Race Conditions, when multiple threads trying to acquire locks concurrently within the locking hierarchy. Imagine now how the lock hierarchy would look like, when you perform a DELETE operation on a table against 20.000 rows. Let’s assume that a row is 400 bytes long, means that 20 records fit onto one page of 8kb

We have now 1 IS lock on database, 1 IS on table, 1000 X on page and 20k on rows. Every lock needs 96 bytes of memory, so we look at 1.9 MB of locks just for 1 simple query. This will not scale indefinitely when you run multiple queries in parallel. For that reason SQL Server implements now the Lock Escalation.

As soon as you have more than 5k locks on one level in your locking hierarchy, SQL Server escalates these many fine-granularity locks into a simple coarse-granularity lock. By default SQL Server always escalates to the table level skipping key page level locks.
Now the above delete operation will have 1 lock on table and 1 on database. But this may impact on concurrency of data, as X lock on table would deny any other read/write operation on that table.
Also In repeatable read isolation level, select statement keeps the lock on till transaction completes so as soon as select statement read more than 5000 rows it will place shared lock on table stopping any further modification.

We can manage lock escalation using sql server to make is it disable or working:
Using trace flag we can disable lock escalation completely on table:
·         1211 – Disables Lock Escalation completely – allows to use 60% of the allocated memory – if 60% of memory is used and more locking is needed you will get an out-of-memory error.
·         1224 – Disables Lock Escalation until the memory threshold of 40% allocated memory is reached – after that Lock Escalation is enabled.

But that was in most cases not a good choice and caused a lot of performance problems. In SQL-Server 2008 and above there is a new table option (ALTER-TABLE) that can be used to change the default Lock-Escalation

Alter table
Set Lock_Escalation =

Auto means if tables is partitioned – the locks will be escalated to the partition-level if table is not partitioned – the locks will be escalated to the table-level, In Table – It will always be escalated to table, Disable-> lock escalation will be deactivated for table.

Lock Escalation needs to be handled carefully, modification on more than 5.000 rows from a table will run into Lock Escalations? You can disable Lock Escalation temporarily, but you have to be very careful here. Another option is to make your DML statements in a loop as different, separate transactions: DML less than 5.000 rows, so that you can prevent Lock Escalations. But it also has its drawback as it may cause frequent log growth issue.

No comments:

Post a Comment