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

原文:[翻译]:SQL死锁-为什么会出现死锁

下面这篇对理解死锁非常重要,首先死锁是如何产生的我们要清楚。

We already know why blocking occurs in the system and howto detect and troubleshoot the blocking issues. Today I’d like us to focus on the deadlocks.First, what is the deadlock? Classic deadlock occurs when 2 processes compete for the resources and waiting on each other. Let’s take a look on that. Click on each picture below to open them in the different window. Let’s assume that Orders table has the clustered index on ID column.Let we have the session 1 that starts transaction and updates the row from the Order table. We already know that Session 1 acquires X lock on this row (ID=1) and hold it till end of transaction

我们已经知道为什么系统中会出现阻塞,也知道如何去探测这些引起阻塞的本质原因。今天我们将重点关注在死锁上。首先,什么是死锁呢?最经典的死锁出现在两个线程为了抢夺同一资源而相互竞争以至于出现你依赖我你依赖我的死循环情况。请看下图的图,我们假定在订单表Id列上有一个聚集索引,会话1开起一个事务去更新订单表的数据。此时会话1会在行数据(ID=1)上申请排它锁至于更新的事务结束。

Now let’s start session 2 and have it update another row in the Orders table. Same situation – session acquires and holds X lock on the row with (ID = 2).

现在,我们开启会话2也更新订单表,不同的是更新的数据行为Id=2,同样的在数据行Id=2上也会申请排它锁至到更新事务的结束。

Now if session 1 tries to acquire X lock on the row with ID = 2 , it cannot do that because Session 2 already held X lock there. So, Session 1 is going to be blocked till Session 2 rollback or commit the transaction

现在,如果会话1尝试在数据行Id=2上申请排它锁,将会受到阻塞,因为会话2已经申请了排它锁。只有当会话2回滚或者提交事务后才能够重新尝试获取排它锁。

It worth to mention that it would happen in any transaction isolation level except SNAPSHOT that handles such conditions differently. So read uncommitted does not help with the deadlocks at all.

这里值得提醒的时,上面的场景需要排除镜像这种特殊优化过的隔离模式。所以从上面的例子来看,read uncommitted隔离模式是不能帮忙我们解决死锁问题的。

Simple enough. Unfortunately it rarely happens in the real life. Let’s see it in the small example using the same dbo.Data table like before. Let’s start 2 sessions and update 2 separate rows in the table (acquire X locks).

 

足够简单,但上面的场景并不常出现。下面我们采用之前使用数据表,我们打开两个会话去更新不同的数据行。

 

Session 1:

会话1,更新ID=0的数据行

Session 2:

会话2,更新ID为40000的数据行

Now let’s run 2 selects.

现在我们再运行两个查询语句

Session 1:

会话1,查询Value=1的数据

Session 2:

会话2,查询Value=40001的数据

Well, as you can see, it introduces deadlock.

如下图所示,我们看到了死锁的相关提示

To understand why it happens, let’s take a look at the execution plan of the select statement:

为了理解到底发生了什么,我们看一相查询所产生的实际执行计划

As you can see – there is the table scan. So let’s think what happened

如上图所示,这是一个表扫描,我们来想一下发生了什么:

  1. First of all, we have 2 X locks on the different rows acquired by both sessions.

          首先,我们有两个排它锁在不同的数据行上,每个会话占用一个。

  1. When session 1 ran select, it introduced table scan. In read committed, repeatable read or serializable isolation levels, readers issue shared S locks, so when session 1 tried to read the row with ID = 40000 (X lock held by session 2) – it was blocked.

          当会话1执行查询时,它会引发表扫描,在三种悲观事务隔离级别事务中(除read uncommitted),读会产生共享锁,所有当会话1尝试去读取Id=40000的数据行时就会出现阻塞,因为会话2更新数据行的事务并未结束。

  1. Same thing happens with session 2 – it’s blocked on the row with ID = 1 (X lock held by session 1).

          同样的情况出现在会话2中,当它尝试去读取ID=1的数据行时,此时由于会话1更新的事务并未结束,所以此次查询也会被阻塞。

So this is the classic deadlock even if there are no data updates involved. It worth to mention that read uncommitted transaction isolation level would not introduce deadlock – readers in this isolation level do not acquire S locks. Although you’ll have deadlock in the case if you change select to update even in read uncommitted level. Otimistic isolation levels also behave differently and we will talk about it later.So as you can see, in the real life as other blocking issues deadlocks happen due non-optimized queries.

这是经典的死锁场景即使此时没有任何相关的数据被更新。这里值得再次提醒的是,在read uncommitted事务隔离级别下是不能减少死锁的,尽管在此模式时并不需要申请共享锁。

        注:本篇文章中一直来讲read uncommitted模式不能解决死锁,在本篇没有举例子,但之前的系列文章中已经有了,可以详细参考。

Next week we will talk how to detect and deal with deadlocks.

下一次我将讲如何探测死锁以及如何处理死锁问题。

时间: 2024-09-20 00:33:00

[翻译]:SQL死锁-为什么会出现死锁的相关文章

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

原文:[翻译]:SQL死锁-锁的类型     很久没有写博客了,这里面的原因有很多.最近的一个项目由于客户明确提出要做下性能压力测试,使用的工具就是VS自带的压力测试工具.以前其它项目做压力测试后反馈的其中一个重要问题就是数据库的死锁.没想到我们这个项目测试时死锁同样的发生了,我之前的项目由于很少参与压力测试,基本上也不会去了解死锁,以及死锁如何解决的问题.     既然有了这个需求,那么要想解决死锁就需要对死锁的相关知识有一定的了解,对于非DBA的来讲并不需要了解的特别深,知道基本概念以及常见

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

原文:[翻译]:SQL死锁-阻塞探测 到了这篇,才是真正动手解决问题的时候,有了死锁之后就要分析死锁的原因,具体就是需要定位到具体的SQL语句上.那么如何发现产生死锁的问题本质呢?下面这篇讲的非常细了,还提到了不少实用的SQL,但对我个人来讲,前半部分基本就够用,可以指出死锁的原因,至于后面那些有兴趣可以多研究研究. As we already know, usually blocking happens due non-optimized queries. But how to detect

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

原文:[翻译]:SQL死锁-死锁排除 As we already saw, the reasons why we have blocking issues and deadlocks in the system are pretty much the same. They occur because of non-optimized queries. So, not surprisingly, troubleshooting techniques are very similar. Let's

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

原文:[翻译]:SQL死锁-锁与事务级别 其实这一篇呢与解决我项目中遇到的问题也是必不可少的.上一篇讲到了各种锁之间的兼容性,里面有一项就是共享锁会引起死锁,如何避免呢,将我们的查询都设置中read uncommitted是否可行呢?其结果显示,当我们当所有的查询都设置成read uncommitted后,后面共享锁死锁基本消除了,看来还是管用的.好了下面接着翻译: Last time we discussed a few major lock types that SQL Server use

[翻译]:SQL死锁-阻塞

原文:[翻译]:SQL死锁-阻塞 一般情况下死锁不是一步到位的,它必须满足特定的条件,然后形成资源的循环依赖才会产生死锁,死锁之前一定会出现阻塞,由阻塞升级才有可能出现死锁,所以我们有必要了解系统中都有哪些已经被阻塞的锁. 我在解决共享锁产生的死锁时,我测试团队的一位同事的问题:既然所有的查询都已经是read uncommitted模式了,为什么还会有死锁呢?下面这篇会回答这个问题. We already know what are the most important lock types a

同时查询一张表-sql server 2008 r2 出现死锁问题

问题描述 sql server 2008 r2 出现死锁问题 程序每3秒钟查询一次,跑一会会出现这种死锁的问题,求助各位大神. 解决方案 SQL Server 2008 R2 安装问题SQL Server 2008 R2 死锁监控SQL Server 2008 R2 安装过程 解决方案二: 死锁频繁出现基本上是程序写的有问题. 建议:查看引起死锁的进程信息 引入事务管理 解决方案三: 插入数据和删除数据都是独占锁,如果要大数据查询可以加 with (nolock) 来取消独占锁.大量数据插入和删

sql server 2000阻塞和死锁问题的查看与解决方法_MsSql

数据库发生阻塞和死锁的现象: 一.数据库阻塞的现象:第一个连接占有资源没有释放,而第二个连接需要获取这个资源.如果第一个连接没有提交或者回滚,第二个连接会一直等待下去,直到第一个连接释放该资源为止.对于阻塞,数据库无法处理,所以对数据库操作要及时地提交或者回滚.二.数据库死锁的现象:第一个连接占有资源没有释放,准备获取第二个连接所占用的资源,而第二个连接占有资源没有释放,准备获取第一个连接所占用的资源.这种互相占有对方需要获取的资源的现象叫做死锁.对于死锁,数据库处理方法:牺牲一个连接,保证另外

SQL Server-聚焦深入理解死锁以及避免死锁建议(三十三)

前言 终于进入死锁系列,前面也提到过我一直对隔离级别和死锁以及如何避免死锁等问题模棱两可,所以才鼓起了重新学习SQL Server系列的勇气,本节我们来讲讲SQL Server中的死锁,看到许多文章都只简述不能这样做,这样做会导致死锁,但是未理解其基本原理,下次遇到类似情况依然会犯错,所以基于了解死锁原理并且得到治疗死锁良方,博主不惜花费多天时间来学习死锁最终总结出本文,若有叙述不当之处请在评论中指出. 死锁定义 死锁是两个或多个进程互相阻塞的情况.两个进程死锁的例子是,进程A阻塞进程B且进程B

sql server 2000阻塞和死锁问题的查看与解决方法

数据库发生阻塞和死锁的现象: 一.数据库阻塞的现象:第一个连接占有资源没有释放,而第二个连接需要获取这个资源.如果第一个连接没有提交或者回滚,第二个连接会一直等待下去,直到第一个连接释放该资源为止.对于阻塞,数据库无法处理,所以对数据库操作要及时地提交或者回滚.二.数据库死锁的现象:第一个连接占有资源没有释放,准备获取第二个连接所占用的资源,而第二个连接占有资源没有释放,准备获取第一个连接所占用的资源.这种互相占有对方需要获取的资源的现象叫做死锁.对于死锁,数据库处理方法:牺牲一个连接,保证另外