一般情况下死锁不是一步到位的,它必须满足特定的条件,然后形成资源的循环依赖才会产生死锁,死锁之前一定会出现阻塞,由阻塞升级才有可能出现死锁,所以我们有必要了解系统中都有哪些已经被阻塞的锁。

我在解决共享锁产生的死锁时,我测试团队的一位同事的问题:既然所有的查询都已经是read uncommitted模式了,为什么还会有死锁呢?下面这篇会回答这个问题。

We already know what are the most important lock types and how transaction isolation levels affect locking behavior. Enough theory – today I’d like to show you simple example why blocking typically occurs in the system.

我们已经知道了最重要的几种锁的类型以及事务隔离级别是如何影响锁行为的。今天我将给大家讲一个例子,展示阻塞是如何发生的。

First, let’s create the table and populate it with the data.

首先,我们创建一个表格以及往这个表格中插入一定的测试数据。

As you can see, this table has 50,000 rows now and 1 clustered index on ID column. Now let’s start another session and run update statement that acquires the lock (update row with ID = Value = 40000). I’m using read committed isolation level but that behavior occurs in any pessimistic isolation level (read uncommitted, read committed, repeatable read and serializable).

这个表格已经有50,000行数据,在Id列上有一个聚集索引。我们另起一个会话用来更新数据。注意,这个更新的事务未提交。

Next, let’s take a look at the list of the locks in the system with sys.dm_tran_locks DMV. I don’t have any other activity in the system but in your case, you can filter results by request_session_id if needed.

下一步,我们从sys.dm_tran_locks中查询所有的锁信息。这个视图由于统计了所有会话的锁信息,如果你查询的一个正在使用中的数据库。,那么显示的信息可能会比较多,你需要根据自己的会话Id过滤下数据结果,我本地因为没有其它的会话,所以不需要过滤。

So we can see 3 active locks: exclusive lock on key (row) level and 2 intent-exclusive locks on the page and table levels.

我们看到了3个锁信息,一个排它锁在行记录上,两个意向排它锁在页级以及数据表对象上。

Now let’s open another session and run select with filter on ID column in the read committed isolation level (you’ll experience the same behavior in repeatable read and serializable isolation levels). This select executes just fine with clustered index seek in the plan.

现在我们打开另外一个会话,在Read comitted 模式下执行一条按Id过滤的查询语句。这条查询语句在聚集索引查找下很顺利的执行成功。

Now let’s change select and replace filter on ID column with filter on Value column. This select should return the same 1 row but it you run it, it would be blocked.

现在,我们更换查询条件,从Id转换成非聚集索引列Value ,这条语句应该返回一行数据,但当你执行时,它将会被阻塞住。

If we query sys.dm_tran_locks again, we can see that the second session is waiting to acquire shared lock.

Let’s terminate the select and take a look at estimated execution plan.

让我们来看一看实时的执行计划

As you can see, the plan changes to clustered index scan. We know that this select returns only 1 row from the table but in order to process the request, SQL Server has to read every row from the table. When it tries to read updated row that held exclusive lock, the process would be blocked (S lock is incompatible with X/IX locks). That’s it – blocking occurs not because multiple sessions are trying to update the same data, but because of non-optimized query that needs to process/acquire lock on the data it does not really need.

就像你看到的,执行计划已经变为聚集索引扫描了。我们知道这个查询只应该返回一条数据,但SQL SERVER为了返回正确的行不得不读取所有行记录。当它尝试读取正在被更新的(已经被上了排它锁)数据行时就会出现阻塞。所以阻塞的发生并不是因为同时有多个会议尝试去更新相同的数据,而是因为没有经过优化的查询申请了锁,但读取到的数据往往是不必要的数据。

Now let’s try to run the same select in read uncommitted mode.

现在,我们在read uncommitted模式下执行相同的语句

As you can see – select runs just fine even with scan. As I already mentioned, in read uncommitted mode, readers don’t acquire shared locks. But let’s run update statement.

如图显示,查询语句在uncommitted模式式正常返回。就像我已经提醒过的,在read uncommitted模式下,读取数据不需要申请共享锁,但我们来试试数据更新

It would be blocked. If you take a look at the lock list, you’ll see that there is the wait on update lock (SQL Server acquires update locks when searches for the data for update)

阻塞出现,我们再看一下锁列表,将会发现一个更新锁,当前的状态为等待。

And this is the typical source of confusions – read uncommitted mode does not eliminate blocking – shared locks are not acquired, but update and exclusive locks are still in the game. So if you downgraded transaction isolation level to read uncommitted, you would not completely solve the blocking issues. In addition to that, you would introduce the bunch of consistency issues. The right way to achieve the goal is to illuminate the source of the problem – non-optimized queries.

这是典型的容易引起混淆的原因所在。read uncommitted模式并不会消除阻塞。共享锁虽然不需要申请了,但更新锁以及排它锁仍然存在。如果你将事务隔离级别降低到read uncommitted,你并不能完全解决阻塞的问题。额外说一下,这样会产生数据不致的问题。正确解决阻塞的方法是说明问题的根源:未经优化的查询。

Next time we will talk how to detect such queries.

下一次我们将讨论如何发现这些未经优化的查询。

[翻译]:SQL死锁-阻塞的更多相关文章

  1. [翻译]:SQL死锁-阻塞探测

    到了这篇,才是真正动手解决问题的时候,有了死锁之后就要分析死锁的原因,具体就是需要定位到具体的SQL语句上.那么如何发现产生死锁的问题本质呢?下面这篇讲的非常细了,还提到了不少实用的SQL,但对我个人 ...

  2. [翻译]:SQL死锁-死锁排除

    As we already saw, the reasons why we have blocking issues and deadlocks in the system are pretty mu ...

  3. [翻译]:SQL死锁-锁与事务级别

    其实这一篇呢与解决我项目中遇到的问题也是必不可少的.上一篇讲到了各种锁之间的兼容性,里面有一项就是共享锁会引起死锁,如何避免呢,将我们的查询都设置中read uncommitted是否可行呢?其结果显 ...

  4. [翻译]:SQL死锁-锁的类型

    很久没有写博客了,这里面的原因有很多.最近的一个项目由于客户明确提出要做下性能压力测试,使用的工具就是VS自带的压力测试工具.以前其它项目做压力测试后反馈的其中一个重要问题就是数据库的死锁.没想到我们 ...

  5. [翻译]:SQL死锁-为什么会出现死锁

    下面这篇对理解死锁非常重要,首先死锁是如何产生的我们要清楚. We already know why blocking occurs in the system and howto detect an ...

  6. SQL死锁知识及解决办法

    [翻译]:SQL死锁-死锁排除 min.jiang 2014-03-18 00:23 阅读:874 评论:1     项目中死锁的解决经历 min.jiang 2014-03-17 01:09 阅读: ...

  7. [SQL]死锁处理语句

    原文:[SQL]死锁处理语句 引言 今天在群里看到分享的解决死锁的sql语句,就想着这东西以后肯定用的着,就下载下来,在这里记录一下,以后查找也方便. SQL SET QUOTED_IDENTIFIE ...

  8. 需要我们了解的SQL Server阻塞原因与解决方法

    需要我们了解的SQL Server阻塞原因与解决方法 上篇说SQL Server应用模式之OLTP系统性能分析.五种角度分析sql性能问题.本章依然是SQL性能 五种角度其一“阻塞与死锁” 这里通过连 ...

  9. sql server 阻塞与锁

    SQL Server阻塞与锁 在讨论阻塞与加锁之前,需要先理解一些核心概念:并发性.事务.隔离级别.阻塞锁及死锁. 并发性是指多个进程在相同时间访问或者更改共享数据的能力.一般情况而言,一个系统在互不 ...

随机推荐

  1. PyCharm4注册码--软件安装

    软件连接:http://www.jetbrains.com/pycharm/ PyCharm4注册码 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...

  2. php读取csv文件,在linux上出现中文读取不到的情况 解决方法

    今,php读取csv文件,在linux上出现中文读取不到的情况,google,后找到解决办法<?phpsetlocale(LC_ALL, 'zh_CN');$row = 1;$handle = ...

  3. DiskGenius无损调整分区大小

    一般情况下,调整分区的大小,通常都涉及到两个或两个以上的分区.比如,要想将某分区的大小扩大,通常还要同时将另一个分区的大小缩小:要想将某个分区的大小缩小,则通常还要同时将另一个分区的大小扩大.    ...

  4. c与c++中的extern const的区别和联系

    最近复习c++,发现了这个东西. c语言里面,我们在一个.c文件中用const定义了一个全局变量后,可以在另一个.c文件中用extern const来引用,但在c++中在链接的时候会报undefine ...

  5. Linux 技巧:让进程在后台可靠运行的几种方法(转)

    下面举了一些例子, 您可以针对不同的场景选择不同的方式来处理这个问题. nohup/setsid/& 场景: 如果只是临时有一个命令需要长时间运行,什么方法能最简便的保证它在后台稳定运行呢? ...

  6. BAPI 调用相当于BAPI_TRANSACTION_COMMIT 的方法

    为什么.net调用SAP的BAPI接口需要调用BAPI_TRANSACTION_COMMIT呢?首先得明白BAPI_TRANSACTION_COMMIT这个BAPI的作用.它功劳很大,在SAP里面很多 ...

  7. ruby 中文字符to_json后乱码(unicode)

    今天遇到一个中文to_json问题 text = "第1章 青豆 不要被外表骗了" text.to_json => "\"\\u7b2c1\\u7ae0 ...

  8. Elasticsearch及java客户端jest使用

    本文使用Github中的Elasticsearch-rtf,已经集成了众多的插件,例如必须使用的中文分词等,可以简单的通过配置来启用中文分词.本文主要分为以下几部分: 1.配置和启用中文分词: 2.定 ...

  9. C++的最佳特性(译)

    最近看到了很多优秀的文章,包括<Why mobile web apps are slow>,实在忍不住翻译出来跟大家分享.这篇文章通过大量的实验和参考文献向我们说明移动应用开发所遇到的问题 ...

  10. HTML5开发手机项目—个人总结

    让网页的宽度自适应屏幕<meta name="viewport" content="width=device-width"/>   1)html上加 ...