SQL Server Lock Escalation - 锁升级

Articles

  1. Locking in Microsoft SQL Server (Part 12 – Lock Escalation)
  2. http://dba.stackexchange.com/questions/12864/what-is-lock-escalation
  3. 2008 R2 Lock Escalation (Database Engine)

   ---Forward from Locking in Microsoft SQL Server (Part 12 – Lock Escalation)

Today I’d like us to talk about Lock Escalation in Microsoft SQL Server. We will cover:

  1. What is Lock Escalation?
  2. How Lock Escalations affects the system
  3. How to detect and troubleshoot Lock Escalations
  4. How to disable Lock Escalation

What is Lock Escalation?

All of us know that SQL Server uses row level locking. Let’s think about
scenario when system modifies the row. Let’s create the small table and
insert 1 row there and next check the locks we have. As usual every
image is clickable.

As you can see there are 4 locks in the picture. shared (S) lock on
the database – e.g. indication that database is in use. Intent exclusive
(IX) lock on the table (OBJECT) – e.g. indication that one of the child
objects (row/key in our case) has the exclusive lock. Intent exclusive
(IX) lock on the page – e.g. same indication about child object
(row/key) exclusive lock. And finally exclusive (X) lock on the key
(row) we just inserted.

Now let’s insert another row in the different session (let’s keep the original Session 1 transaction uncommitted).

When we check the locks we will see that there are 8 locks – 4 per
session. Both sessions ran just fine and don’t block each other.
Everything works smooth – that great for the concurrency. So far so
good. The problem though is that every lock takes some memory space –
128 bytes on 64 bit OS and 64 bytes on 32 bit OS). And memory is not the
free resource. Let’s take a look at another example. I’m creating the
table and populating it with 100,000 rows. Next, I’m disabling the lock
escalation on the table (ignore it for now) and clear all system cache
(don’t do it in production). Now let’s run the transaction in repeatable
read isolation level and initiate the table scan.

Transaction is not committed and as we remember, in repeatable read isolation level SQL Server holds the locks till end of transaction. And now let’s see how many locks we have and how much memory does it use.

As you can see, now we have 102,780 lock structures that takes more than
20MB of RAM. And what if we have a table with billions of rows? This is
the case when SQL Server starts to use the process that called “Lock
Escalation” – in nutshell, instead of keeping locks on every row SQL
Server tries to escalate them to the higher (object) level. Let’s see
how it works.

First we need to commit transaction and clear the cache. Next, let’s
switch lock escalation for Data table to AUTO level (I’ll explain it in
details later) and see what will happen if we re-run the previous
example.

As you can see – just 2 locks and only 1Mb of RAM is used (Memory
clerk reserves some space). Now let’s look what locks do we have:

As you can see there is the same (S) lock on the database and now we
have the new (S) shared lock on the table. No locks on page/row levels
are kept. Obviously concurrency is not as good as it used to be. Now,
for example, other sessions would not be able to update the data on the
table – (S) lock is incompatible with (IX) on the table level. And
obviously, if we have lock escalation due data modifications, the table
would hold (X) exclusive lock – so other sessions would not be able to
read the data either.

The next question is when escalation happens. Based on the
documentation, SQL Server tries to escalate locks after it acquires at
least 5,000 locks on the object. If escalation failed, it tries again
after at least 1,250 new locks. The locks count on index/object level.
So if Table has 2 indexes – A and B you have 4,500 locks on the index A
and 4,500 locks on the index B, the locks would not be escalated. In
real life, your mileage may vary – see example below – 5,999 locks does
not trigger the escalation but 6,999 does.

How it affects the system?

Let’s re-iterate our first small example on the bigger scope. Let’s
run the first session that updates 1,000 rows and check what locks are
held.

As you see, we have intent exclusive (IX) locks on the object (table)
and pages as well as various (X) locks on the rows. If we run another
session that updates completely different rows everything would be just
fine. (IX) locks on table are compatible. (X) locks are not acquired on
the same rows.

Now let’s trigger lock escalation updating 11,000 rows.

As you can see – now the table has exclusive lock. So if you run the
session 2 query from above again, it would be blocked because (X) lock
on the table held by session 1 is incompatible with (IX) lock from the
session 2.

When it affects us? There are 2 very specific situations

  1. Batch inserts/updates/deletes. You’re trying to import thousands of
    the rows (even from the stage table). If your import session is lucky
    enough to escalate the lock, neither of other sessions would be able to
    access the table till transaction is committed.
  2. Reporting – if you’re using repeatable read or serializable
    isolation levels in order to have data consistent in reports, you can
    have (S) lock escalated to the table level and as result, writers will
    be blocked until the end of transaction.

And of course, any excessive locking in the system can trigger it too.

How to detect and troubleshoot Lock Escalations

First of all, even if you have the lock escalations it does not mean
that it’s bad. After all, this is expected behavior of SQL Server. The
problem with the lock escalations though is that usually customers are
complaining that some queries are running slow. In that particular case
waits due lock escalations from other processes could be the issue. If
we look at the example above when session 2 is blocked, and run the
script (as the session 3) that analyzes sys.dm_tran_locks DMV, we’d see
that:

I’m very heavy on the wait statistics as the first troubleshooting tool (perhaps heavier than I need to be 
). One of the signs of the issues with lock escalations would be the
high percent of intent lock waits (LCK_M_I*) together with relatively
small percent of regular non-intent lock waits. See the example below:

In case if the system has high percent of both intent and regular
lock waits, I’d focus on the regular locks first (mainly check if
queries are optimized). There is the good chance that intent locks are
not related with lock escalations.

In addition to DMVs (sys.dm_tran_locks, sys.dm_os_waiting_tasks,
sys.dm_os_wait_stats, etc), there are Lock Escalation Profiler event and
Lock Escalation extended event you can capture. You can also monitor
performance counters related with locking and create the baseline
(always the great idea)

Last but not least, look at the queries. As I mentioned before
in most part of the cases excessive locking happen because of
non-optimized queries. And that, of course, can also trigger the lock
escalations.

How to disable Lock Escalation

Yes, you can disable Lock Escalations. But it should be the last
resort. Before you implement that, please consider other approaches

  1. For data consistency for reporting (repeatable read/serializable isolation levels) – switch to optimistic(read committed snapshot, snapshot) isolation levels
  2. For batch operations consider to either change batch size to be
    below 5,000 rows threshold or, if it’s impossible, you can play with
    lock compatibility. For example have another session that aquires IS
    lock on the table while importing data. Or use partition switch from the
    staging table if it’s possible

In case if neither option works for you please test the system before you disable the lock escalations. So:

For both SQL Server 2005 and 2008 you can alter the behavior on the
instance level with Trace Flags 1211 and 1224. Trace flag 1211 disables
the lock escalation in every cases. In case, if there are no available
memory for the locks, the error 1204 (Unable to allocate lock resource)
would be generated. Trace flag 1224 would disable lock escalations in
case if there is no memory pressure in the system. Although locks would
be escalated in case of the memory pressure.

With SQL Server 2005 trace flags are the only options you have. With
SQL Server 2008 you can also specify escalation rules on the table level
with ALTER TABLE SET LOCK_ESCALATION statement. There are 3 available
modes:

    1. DISABLE – lock escalation on specific table is disabled
    2. TABLE (default) – default behavior of lock escalation – locks are escalated to the table level.
    3. AUTO – if table is partitioned, locks would be escalated to
      partition level when table is partitioned or on table level if table is
      not partitioned
时间: 2024-10-19 14:05:08

SQL Server Lock Escalation - 锁升级的相关文章

SQL Server中的锁的简单学习

原文:SQL Server中的锁的简单学习 简介 在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查询的.这些查询并不会像绅士那样排队等待执行,而是会找最短的路径执行.因此,就像十字路口需要一个红绿灯那样,SQL Server也需要一个红绿灯来告诉查询:什么时候走,什么时候不可以走.这个红绿灯就是锁. 图1.查询可不会像绅士们那样按照次序进行排队 为什么需要

T-SQL查询进阶—理解SQL Server中的锁

在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查询的.这些查询并不会像绅士那样排队等待执行,而是会找最短的路径执行.因此,就像十字路口需要一个红绿灯那样,SQL Server也需要一个红绿灯来告诉查询:什么时候走,什么时候不可以走.这个红绿灯就是锁. 图1.查询可不会像绅士们那样按照次序进行排队 为什么需要锁 在开始谈锁之前,首先要简单了解一下事务和事务的

SQL Server中的锁

NOLOCK(不加锁) 此选项被选中时,SQL Server 在读取或修改数据时不加任何锁. 在这种情况下,用户有可能读取到未完成事务(Uncommited Transaction)或回滚(Roll Back)中的数据, 即所谓的“脏数据”. HOLDLOCK(保持锁) 此选项被选中时,SQL Server 会将此共享锁保持至整个事务结束,而不会在途中释放. UPDLOCK(修改锁) 此选项被选中时,SQL Server 在读取数据时使用修改锁来代替共享锁,并将此锁保持至整个事务或命令结束.使用

SQL Server中的锁类型及用法

一. 为什么要引入锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 丢失更新 A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订票系统 脏读 A用户修改了数据,随后B用户又读出该数据,但A用户因为某些原因取消了对数据的修改,数据恢复原值,此时B得到的数据就与数据库内的数据产生了不一致 不可重复读 A用户读取数据,随后B用户读出该数据并修改,此时A用户再读取数据时发现前后两次的值不一致 并发控制的主要方法是封锁,锁就是在一段时间内禁止用户做某些

sql server中的锁 事务锁 更新锁 保持锁 共享锁 你知道吗?

锁定数据库的一个表 SELECT * FROM table WITH (HOLDLOCK) 注意: 锁定数据库的一个表的区别 SELECT * FROM table WITH (HOLDLOCK) 其他事务可以读取表,但不能更新删除 SELECT * FROM table WITH (TABLOCKX) 其他事务不能读取表,更新和删除 SELECT 语句中"加锁选项"的功能说明 SQL Server提供了强大而完备的锁机制来帮助实现数据库系统的并发性和高性能.用户既能使用SQL Ser

SQL Server中的锁可以分为如下几类

从大类来看,SQL Server中的锁可以分为如下几类: 共享锁(S锁):用于读取资源所加的锁.拥有共享锁的资源不能被修改.共享锁默认情况下是读取了资源马上被释放.比如我读100条数据,可以想像成读完了第一条,马上释放第一条,然后再给第二条数据上锁,再释放第二条,再给第三条上锁.以此类推直到第100条.这也是为什么我在图9和图10中的查询需要将隔离等级设置为可重复读,只有设置了可重复读以上级别的隔离等级或是使用提示时,S锁才能持续到事务结束.实际上,在同一个资源上可以加无数把S锁. 排他锁(X锁

快钱支付与Sql Server的乐观锁和悲观锁

在实际的多用户并发访问的生产环境里边,我们经常要尽可能的保持数据的一致性.而其中最典型的例子就是我们从表里边读取数据,检查验证后对数据进行修改,然后写回到数据库中.在读取和写入的过程中,如果在多用户并发的环境里边,其他用户已经把你要修改的数据进行了修改是非常有可能发生的情况,这样就造成了数据的不一致性. 最近在做快钱支付的时候就碰到了这个问题,原来的代码如下:1. 表Order的结构:    OrderId   int 自增长    Status   nvarchar(10)  //未处理时的状

SQL SERVER 数据库的锁

1SQL SERVER 锁的概念 共享锁:用于读取资源所加的锁.拥有共享锁的资源不能被修改.共享锁在默认情况下是读取了资源马上被释放. 排他锁:和其他锁都不兼容,包括其他排他锁,排它锁用于修改数据,当资源上加了排他锁时,其他请求读取或修改这个资源的事物都会被阻塞,直到排他锁被释放为止. 更新锁:是共享锁和排它锁的结合,用于更新数据,更新数据时首先需要找到被更新的数据,此时可以理解为被查找的数据上了共享锁.当找到需要修改的数据时,需要对被修改的资源上排他锁. sql server 通过更新锁来避免

SQL Server 死锁 (Page锁)诊断

在数据库中打开死锁监测可以收集到数据库发生的死锁情况.打开的方式有2种: 1 打开1222监控 执行SQL语句: Dbcc traceon(1222,-1); 然后在系统日志里查看死锁的信息. 2 启动SQL Profiler(建议使用): 下面就是一个发生死锁的实例图: 下面提供对这个死锁分析思路,如有不当之处,还望大家批评指正. 一共3个问题,下面逐个回答. 第一个问题:被锁定的资源是什么? 上面写的很清楚,是一个Page 锁, 那么Page 锁是什么呢? 通常死锁是你操作A表,然后又要操作