在这篇随笔中,我们的主要关注点在 Key-Range Lock。Key-Range Lock有 S-S、S-U、I-N、X-X几种情况。我们一个一个来说,力求明白。遗憾的是,这里可能会比较冗长,那么死锁分析只好依次顺延了。

Range S-S锁的获取规则

MSDN 对 Range 锁的规则有部分描述,但是言简意赅,以下我们会将各种情况分解开来,理清MSDN中涉及的或者未涉及的规则,这些规则适用于SQL Server 2000/2005/2008/2008 R2。关于MSDN的描述,请参见:http://technet.microsoft.com/zh-cn/library/ms191272(en-us,SQL.110).aspx。

在描述规则之前需要声明的是,我们的聚集索引就建立在 WHERE 字句之上,这很重要,否则是不会获得 Range 锁的,也就达不到 SERIALIZABLE 的要求了;另外,为了讨论简便,以下的 SQL 全部省略 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 的声明。

我们假设有以下的表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE [dbo].[MyTable](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [index_column] [int] NOT NULL,
    [data] [int] NOT NULL,
    CONSTRAINT [PK_MyTable] PRIMARY KEY NONCLUSTERED
    (
        [id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
 
CREATE UNIQUE CLUSTERED INDEX [IX_MyTable] ON [dbo].[MyTable]
(
    [index_column] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

并假设我们有如下的数据:

1
2
3
4
5
6
7
8
9
10
INSERT INTO [MyTable] ([index_column],[data]) VALUES (1, 1)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (2, 2)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (3, 3)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (4, 4)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (5, 5)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (15, 6)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (16, 7)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (18, 8)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (25, 9)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (30, 10)

那么这张表看起来应该是这样的(我另外还将Index的Hash值以及row所在的数据页Dump出来了,以便咱们做实验)。

id index_column data index hash row page
1 1 1 (8194443284a0) 78
2 2 2 (61a06abd401c) 78
3 3 3 (98ec012aa510) 78
4 4 4 (a0c936a3c965) 78
5 5 5 (59855d342c69) 78
6 15 6 (f1de2a205d4a) 78
7 16 7 (f07ed88b2b23) 78
8 18 8 (e9069d930a93) 78
9 25 9 (b81181109ebc) 78
10 30 10 (8034b699f2c9) 78

对于WHERE子句中的条件命中现有记录的情况

规则一:如果 WHERE 子句使用的是“相等”条件,例如“WHERE [index_column]=6”,并且该索引是唯一索引,则该索引不会获得Key-Range S-S锁,仅仅是Key上获得普通S锁;

假设我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=1

那么我们使用 sp_lock 得到锁的情况:

可以发现第一个索引上获得了S锁,但并不是 Range S-S 锁。

规则二:如果 WHERE 子句使用的是“范围”条件,例如“>、<、BETWEEN、IN”等。不论该索引是否唯一,WHERE子句规定都会成为 Range S-S 锁作用的范围,除此之外,在索引排序规则之下,这个作用范围的“下一个”索引项也会获得Range S-S锁。

我们必须首先解释一下“下一个”是怎么一回事,“下一个”索引项有两种情况:

第一:如果在索引排序规则下,作用范围之外按照数据排布的方向能够找到一个存在的,或者是“残存的”索引项(已经提交删除,数据库中再也看不到了,但是还没有从B树数据页中删除),那么这个索引项就是“下一个”索引项;

第二:如果在索引排序规则下,作用范围之外按照数据排布的方向找不到任何残存的索引项,那么无限远(Resource Hash为0xffffffff)的索引项就是“下一个”索引项。

我们结合规则二进行说明,例如我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>=1 AND [index_column]<=4

那么 index_column 中的值为 1、2、3、4的索引会获得 Range S-S 锁,除此以外,4之后的下一个索引值,也就是5对应的索引会获得 Range S-S锁。这和我们的实验结果刚好一致。

我们再来看着一个,例如我们执行:

SELECT [data] FROM [MyTable] WHERE [index_column]>=20 AND [index_column]<=40

那么 index_column 为 25、30的索引会获得 Range S-S 锁,除此以外,30之后的下一个索引值,也就是“无限远”会获得 Range S-S 锁,请看实际Dump的锁的使用情况:

我们最后练一个稍稍复杂点儿情况:

SELECT [data] FROM [MyTable]

WHERE ([index_column]>=2 AND [index_column]<=4) OR ([index_column]>=10 AND [index_column]<=16) OR ([index_column]>=30 AND [index_column]<=40)

这里想说明的问题是,我们的“范围”是指一个个的闭合的范围,要一个个套用规则进行分析,我们现在有3块儿闭合的范围,分别是 [2,4]、[10,16]、[30,40]。我们一个个的来,对于[2,4],在这个范围内2,3,4,5获得 Range S-S锁;

对于[10,16]范围,15,16,18获得 Range S-S锁;对于[30,40]范围,30,无限远获得 Range S-S锁,一共9个。

规则一补充:如果 WHERE 子句使用的是“相等”条件,但是该索引不是唯一索引,那么除了WHERE命中的索引获得 Range S-S锁之外,“下一个”索引也会获得 Range S-S锁。

我今天仔细的做了关于这个规则的验证。另外查阅了 SQL Server 2000 - 2008 Internals 的图书中关于这个问题的记载。在不是唯一索引的情况下,没有以上这种固定的选择规则。以上规则只有在一些特定情况下才出现。而其他规则是没有问题的。

对于WHERE子句中的条件不能命中任何记录的情况

规则三:如果 WHERE 子句使用的是“相等”条件,不论索引是否为唯一索引,若不能够命中任何记录,除该 WHERE 子句规定的那个不存在的记录作为 Range S-S的一部分之外,该记录的“下一个”索引值也将会获得 Range S-S 锁。

例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=6

那么下一条索引记录为15所对应的索引,因此这个索引将会获得 Range S-S 锁。

又例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=31

那么下一索引记录应该是“无限远”对应的索引,则这个索引将会获得 Range S-S 锁。

规则四:如果WHERE子句中使用“范围”条件,不论索引是否为唯一索引,若不能够命中任何记录,除该 WHERE 子句规定的那个不存在的范围作为 Range S-S的一部分外,该范围的“下一个”索引值也将会获得 Range S-S锁。

例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>=6 AND [index_column]<=10

我实在是写不动了,请各位开动脑筋吧,这里直接给结果:

再来一个例子吧,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>30 AND [index_column]<40

结果是:

好了,这一篇终于搞定了。下一篇我们到了 Range S-U 以及 Range I-N 这下会死锁了,有好戏看了。

SQL Server 的事务和锁(二)-Range S-S锁的更多相关文章

  1. (转)SQL Server 的事务和锁(一)

    SQL Server 的事务和锁(一)   最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁: 1 2 3 4 5 6 7 8 9 1 ...

  2. SQL Server 之 事务与隔离级别实例讲解

    SQL Server 之 事务与隔离级别实例讲解 SQL Server 实现了6个隔离级别来防止并发情况下,类似企图并发的访问或修改同一数据时问题的发生.本文将带你体验全部6个隔离级别.正如你接下来将 ...

  3. SQL Server中事务、锁定和阻塞

    事务是什么 在SQL Server中事务是构成一个工作逻辑单元的一系列任务,也就说多个任务放在一起执行,这些任务要么全部执行成功,要么全部执行失败. 通过事务我们可以保证数据的完整性,例如:用户A给用 ...

  4. 如何读懂SQL Server的事务日志

    简介 本文将介绍SQL Server的事务日志中记录了哪一些信息,如何来读懂这些事务日志中信息.首先介绍一个微软没有公开的函数fn_dblog,在文章的接下来的部分主要用到这个函数来读取事务日志. f ...

  5. Step2:SQL Server 复制事务发布

    一.背景 在复制的运用场景中,事务发布是使用最为广泛的,我遇到这样一个场景:在Task数据库中有Basic与Group两个表,需要提供这两个表的部分字段给其它程序读取放入缓存,程序需要比较及时的获取到 ...

  6. SQL Server 2000事务复制问题

    2000现在用的估计不多了,把之前收集的一些复制问题整理发布出来.可能都是些很白很二的问题,但人总是由最初的无知不断成长●-● SQL Server 2000事务复制问题服务器A(发布) 服务器B(分 ...

  7. SQL Server提高事务复制效率优化(一)总体概述

      随着公司业务的发展,数据量增长迅速,在解决Scale Out的同时,还要考虑到主从的复制延迟问题,尽量降到1s以内满足线上业务,如果不调整,SQL Server默认的配置可能平均要3s左右.生产的 ...

  8. SQL SERVER 分布式事务(DTC)

    BEGIN DISTRIBUTED TRANSACTION指定一个由 Microsoft 分布式事务处理协调器 (MS DTC) 管理的 Transact-SQL 分布式事务的起始. 语法BEGIN ...

  9. SQL Server 2008空间数据应用系列二:空间索引(Spatial Index)基础

    原文:SQL Server 2008空间数据应用系列二:空间索引(Spatial Index)基础 在前一篇博文中我们学习到了一些关于地理信息的基础知识,也学习了空间参照系统,既地球椭球体.基准.本初 ...

  10. 第十七周翻译-SQL Server中事务日志管理的阶梯,级别5:以完全恢复模式管理日志

    SQL Server中事务日志管理的阶梯,级别5:以完全恢复模式管理日志 作者:Tony Davis,2012/01/27 翻译:赖慧芳 译文: 该系列   本文是Stairway系列的一部分:SQL ...

随机推荐

  1. Cloud_panel

    传统基础架构应用程序的系统架构师,云计算应用程序的设计确实是相当有挑战性的工作.体现在应用程序架构师首先要了解云计算环境和传统基础架构的差异并且充分利用云计算平台的一些特点来更好的满足用户需求. 对于 ...

  2. 转】Maven学习总结(九)——使用Nexus搭建Maven私服

    原博文出自于:http://www.cnblogs.com/xdp-gacl/p/4068967.html 感谢! 一.搭建nexus私服的目的 为什么要搭建nexus私服,原因很简单,有些公司都不提 ...

  3. Android教程说明-夜神模拟器连接IDE更新让Delphi发现你的手机或夜神模拟器

    相关资料: [深圳]jiuk 发布 1.官网下载模拟器http://www.bignox.com/并运行 2.打开开发者选项刚开始是看不到的->关于平板电脑->多点几次版本号->打开 ...

  4. gdb之watch命令

    [gdb之watch命令] 什么是watchpoint? watchpoint,顾名思义,其一般用来观察某个变量/内存地址的状态(也可以是表达式),如可以监控该变量/内存值是否被程序读/写情况. 在g ...

  5. 自然对数e

    上学时课本里提到过,有一种以无理数e=2.71828--为底数的对数,称为自然对数.当时老师并没有讲明白这是个啥东西.并且还有一个很奇怪的极限,也是靠记忆的,完全不理解. \[\lim_{n\to\i ...

  6. Cisco SDM

    SDM连接方式:http+telnet / https+ssh   要使用SDM对CISCO设备实现集中式管理,必须在设备上键入如下命令:   步骤1: 要启用路由器的HTTP/HTTPS 服务器,请 ...

  7. CCS5 编译器手动设置dsp支持可变参数宏等问题

    IDE:CSS5.4,compiler不支持可变参数宏.需要手动设置编译器相关选项: Language Option->Language Mode —>no strict ANSI. 1. ...

  8. PowerDesigner 表视图修改

    PowerDesigner中Table视图同时显示Code和Name,像下图这样的效果: 实现方法:Tools-Display Preference 转自:http://www.shaoqun.com ...

  9. 如何加入自定义WebControl

    http://www.screencast.com/users/Dennis.Garavsky/folders/Default/media/c75b4ec6-1641-4f82-936e-39360d ...

  10. Javascript模块规范(CommonJS规范&&AMD规范)

    Javascript模块化编程(AMD&CommonJS) 前端模块化开发的价值:https://github.com/seajs/seajs/issues/547 模块的写法 查看 AMD规 ...