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

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

其实这一篇呢与解决我项目中遇到的问题也是必不可少的。上一篇讲到了各种锁之间的兼容性,里面有一项就是共享锁会引起死锁,如何避免呢,将我们的查询都设置中read uncommitted是否可行呢?其结果显示,当我们当所有的查询都设置成read uncommitted后,后面共享锁死锁基本消除了,看来还是管用的。好了下面接着翻译:

Last time we discussed a few major lock types that SQL Server uses. Shared(S), Exclusive(X) and Update(U). Today I’d like to talk about transaction isolation levels and how they affect locking behavior. But first, let’s start with the question: “What is transaction?”

上一次我们讨论了一些主要的SQL SERVER锁类型:共享锁(S),排它锁(X),以及更新锁(U)。今天我们来讲事务级别是如何影响锁的行为的。但在这之前,我们需要从一个问题开始:“什么是事务”?

Transaction is complete unit of work. Assuming you transfer money from checking account to saving, system should deduct money from the checking and add it to the saving accounts at once. Even if those are 2 independent operations, you don’t want it to “stop at the middle”, well at least in the case if bank deducts it from the checking first If you don’t want to take that risk, you want them to work as one single action.

事务是一个完整的单元工作模式。假如你从支票帐户中将钱转移到储蓄卡中,银行系统首先会从你的支票帐户中扣钱,然后再往你的储蓄卡中存钱。即使这是两个相互独立的操作,你也不想让其在中间的某一步停止,至少不能停止在银行将你的钱从支票帐户中扣除之后 。如果你不冒这个风险,那么你希望这两步操作最好是一步操作来完成。

There is useful acronym – ACID – that describes requirements to transaction:

这里有一个非常有用的编写-ACID,它将描述事务的需求:

  • (A) – Atomicity or “all or nothing”. Either all changes are saved or nothing changed.

        (A)-它代表所有或者是无,要么全部保存要么不保存任何数据

  • (C) – Consistency. Data remains in consistent stage all the time

        (C)-数据每时每刻要保持一致性

  • (I) – Isolation. Other sessions don’t see the changes until transaction is completed. Well, this is not always true and depend on the implementation. We will talk about it in a few minutes

        (I)-数据隔离,其它的会话看不到事务未提交的数据。这句并不总是正确的,有时依赖于系统的实现,我们后续会讲到。

  • (D) – Durability. Transaction should survive and recover from the system failures

        (D)-数据可以回滚,当事务执行出现异常的情况下

There are a few common myths about transactions in SQL Server. Such as:

下面是一些公共的关于事务的错误观点,例如:

  • There are no transactions if you call insert/update/delete statements without begin tran/commit statements. Not true. In such case SQL Server starts implicit transaction for every statement. It’s not only violate consistency rules in a lot of cases, it’s also extremely expensive. Try to run 1,000,000 insert statements within explicit transaction and without it and notice the difference in execution time and log file size.

       当我们直接写insert/update/delete这句语句时,如果没有显示的写begin tran/commit 这类语句就不存在事务。这是不正确的,实际上SQL SERVER 会隐式的为每次SQL操作都加了事务。这不光违反了数据一致性规则且往往造成的后果是非常昂贵的。可以去尝试往一个表中插入1000000条数据,第一种显示的加上事务语句,第二种不加事务语句,执行之后对比下执行的时间以及日志大小的不同。

  • There is no transactions for select statements. Not true. SQL Server uses (lighter) transactions with select statements.

        当执行select语句时没有事务。这是不正确的,SQL SERVER会使用轻量级的事务。

  • There is no transactions when you have (NOLOCK) hint. Not true. (NOLOCK) hint downgrades the reader to read uncommitted isolation level but transactions are still in play.

        当们们在select语句后面加了nolock后,就没有事务了。这也是不正确的。nolock只是降低了事务必有隔离级别为read uncommitted而已并不是没有事务。

Each transaction starts in specific transaction isolation level. There are 4 “pessimistic” isolation levels: Read uncommitted, read committed, repeatable read and serializable and 2 “optimisitic” isolation levels: Snapshot and read committed snapshot. With pessimistic isolation levels writers always block writers and typically block readers (with exception of read uncommitted isolation level). With optimistic isolation level writers don’t block readers and in snapshot isolation level does not block writers (there will be the conflict if 2 sessions are updating the same row). We will talk about optimistic isolation levels later.

每个事务都在指定的事务级别中,这里有四种悲观事务必有隔离级别:Read uncommitted (允许脏读),read committed(不允许脏读),repeatable(可重复读),serialzable以及两种经过优化后的事务级别:Snapshot 以及read committed snapshot。

     注:这里事务隔离级别比较多,我理解不也太多,就省略掉了。我们比较常见的就是前面的两种,允许脏读以及不允许脏读的情况。至于后面的有关镜像相关的内容这里我不做多的翻译。

Regardless of isolation level, exclusive lock (data modification) always held till end of transaction. The difference in behavior is how SQL Server handles shared locks. See the table below:

排它锁不管事务级别,它总是占用锁到整个事务结束:


So, as you can see, in read uncommitted mode, shared locks are not acquired – as result, readers (select) statement can read data modified by other uncommitted transactions even when those rows held (X) locks. As result any side effects possible. Obviously it affects (S) lock behavior only. Writers still block each other.

所以,就像你看到的,如果在允许脏读的模式下,是不需要申请共享锁的,可以读取到其实事务还未完全提交的数据,即使这些数据已经被加上了排它锁。但这只影响共享锁,对于写的会话仍然会存在相互阻塞甚至死锁的情况。

In any other isolation level (S) locks are acquired and session is blocked when it tries to read uncommitted row with (X) lock. In read committed mode (S) locks are acquired and released immediately. In Repeatable read mode, (S) locks are acquired and held till end of transaction. So it prevents other session to modify data once read. Serializable isolation level works similarly to repeatable read with exception that locks are acquired on the range of the rows. It prevents other session to insert other data in-between once data is read.

共享锁可以任意事务隔离级别中发生,当它尝试去读取其它事务未提交的数据(行上加了排它锁)时就是会阻塞。在Read committed 模式下,共享锁的申请以及释放都是非常迅速的。在Repeatable read模式下,共享锁被申请后一直占用到事务结束,它保证其它会话不编辑其已经读取到的数据。Serializable 模式的工作方式和Repeatable非常相似,但它会锁定一定范围的数据,访问其它会话插入数据。

注:这块还没理解到位,后续有时间再补充下。

You can control that locking behavior with “set transaction isolation level” statement – if you want to do it in transaction/statement scope or on the table level with table hints. So it’s possible to have the statement like that:

在你的事务中或者是表级间的查询你可以通过设置事务隔离级别来控制锁行为,就像下面的查询语句:

So you access Table1 in read uncommitted isolation level and Table2 in serializable isolation level.

这条语句的作用就是你可以对Table1读取其它事务未提交的数据,以serializable隔离级别读取Table2的数据。

It’s extremely easy to understand the difference between transaction isolation levels behavior and side effects when you keep locking in mind. Just remember (S) locks behavior and you’re all set.

这将非常容易理解事务隔离级别行为之间的差别以及它们的副作用,你只需要记住共享锁以及你所有的设置。

Next time we will talk why do we have blocking in the system and what should we do to reduce it.

下一次我们将会讲到为什么我们的系统中会存在阻塞以及我们如何做才能减少阻塞的发生

时间: 2024-10-26 16:35:25

[翻译]:SQL死锁-锁与事务级别的相关文章

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

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

[翻译]:SQL死锁-阻塞

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

[翻译]: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死锁-为什么会出现死锁 下面这篇对理解死锁非常重要,首先死锁是如何产生的我们要清楚. 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 o

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

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

SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因

原文:SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因 原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中的事务概念,ACID 原则,事务中常见的问题,问题造成的原因和事务隔离级别等这些方面的知识好好的整理了一下. 其实有关 SQL Server 中的事务,说实话因为内容太多, 话题太广,稍

高性能MySql学习笔记——锁、事务、隔离级别(转)

为什么需要锁? 因为数据库要解决并发控制问题.在同一时刻,可能会有多个客户端对Table1.rown进行操作,比如有的在读取该行数据,其他的尝试去删除它.为了保证数据的一致性,数据库就要对这种并发操作进行控制,因此就有了锁的概念. 锁的分类 从对数据操作的类型(读\写)分 读锁(共享锁):针对同一块数据,多个读操作可以同时进行而不会互相影响. 写锁(排他锁):当当前写操作没有完成前,它会阻断其他写锁和读锁. 从锁定的数据范围分 表锁 行锁 为了尽可能提高数据库的并发度,每次锁定的数据范围越小越好

SQL Server锁分区特性引发死锁解析

原文:SQL Server锁分区特性引发死锁解析 锁分区技术使得SQL Server可以更好地应对并发情形,但也有可能带来负面影响,这里通过实例为大家介绍,分析由于锁分区造成的死锁情形. 前段时间园友@JentleWang在我的博客锁分区提升并发,以及锁等待实例中问及锁分区的一些特性造成死锁的问题,这类死锁并不常见,我们在这里仔细分析下.不了解锁分区技术的朋友请先看下我的锁分区那篇实例. Code(执行测试脚本时请注意执行顺序,说明) 步骤1 创建测试数据 use tempdb go creat

sqlserver2008-各位大神,请问sql的两个事务中的select如何能导致死锁

问题描述 各位大神,请问sql的两个事务中的select如何能导致死锁 捕获的trace日志非常大,我先放下出错的两条语句. sqlserver profiler捕获的是这样一条错误. 我想知道的是明明是两条select,S锁为何会导致死锁.而且死锁图形中的的排它锁是怎么回事,明明对keeping的这个资源没有update,只有delete,delete也会增加排它锁吗?行级的,还是表级的,为何我在prfiler中 捕获update或者delete时mode列没有提示锁? 问的有点多,请先看下图