sql server中select语句需要申请的锁

以NA_TrafficMemberOrderRelation表为例,表的索引如下:

index_id name cols
1 PK__NA_Traff__FB6751642649A903 TrafficMemberOrderRelationId
26 IX_NA_TrafficMemberOrderRelation_usermobile UserMobile

下面的查询语句,正常情况下会先使用IX_NA_TrafficMemberOrderRelation_usermobile索引进行查找,再返回聚集索引查找剩下的列

select * from NA_TrafficMemberOrderRelation where usermobile='13719805324' and ecprdcode='50615801625'

执行计划如下:

因为在read committed隔离级别上,查询语句申请的锁,会马上释放,所以把隔离级别设置为可重复读(repeatable read),再开启事务后运行查询语句,但不提交事务

set transaction isolation level repeatable read;
begin tran
select * from NA_TrafficMemberOrderRelation with(index=PK__NA_Traff__FB6751642649A903) where usermobile='13719805324' and ecprdcode='50615801625'

然后运行 exec sp_lock来查看申请的锁:

spid dbid ObjId IndId Type Resource Mode Status
58 17 610361489 1 PAG 1:8005696                        IS GRANT
58 17 610361489 26 KEY (525b6b18cbd1)                   S GRANT
58 17 610361489 26 PAG 4:53295                          IS GRANT
58 17 610361489 1 KEY (b1b78d542d80)                   S GRANT
58 17 610361489 26 KEY (6e79de43f52b)                   S GRANT
58 17 610361489 0 TAB   IS GRANT
58 17 610361489 1 KEY (8d95380f137a)                   S GRANT

图中看出,查询语句申请的锁如下:

1、对象上的意向共享锁(IS)

58 17 610361489 0 TAB   IS GRANT

2、UserMobile索引页面上的意向共享锁(IS)

58 17 610361489 26 PAG 4:53295                          IS GRANT

3、符合条件的键值上的共享锁(S),因为手机号码13719805324有两条记录,所以申请了两个共享锁

58 17 610361489 26 KEY (525b6b18cbd1)                   S GRANT
58 17 610361489 26 KEY (6e79de43f52b)                   S GRANT

4、通过UserMobile索引找到的第一行,都会通过主键去聚集索引查找这一行以获取其他列的数据,所以会在聚集索引上申请跟2、3步一要样的锁(页上的IS锁和键上的S锁):

58 17 610361489 1 PAG 1:8005696                        IS GRANT
58 17 610361489 1 KEY (b1b78d542d80)                   S GRANT
58 17 610361489 1 KEY (8d95380f137a)                   S GRANT

所以,通过索引查找来获取数据的查询,大致总结如下:

1、对使用到的PAGE加IS锁

2、对使用到的每一个索引键或聚集索引键加共享锁

下面看下在没有索引的情况,通过表扫描,需要申请哪些锁(先通过alter table NA_TrafficMemberOrderRelation set(lock_escalation=disable)禁止表上的索升级,防止直接升级为表上的S锁):

<span style="font-family: Arial, Helvetica, sans-serif;">select * from NA_TrafficMemberOrderRelation where CreateTime='2015-10-25 05:29:47.000'</span>

CreateTime字段没有索引,所以上面的查询会使用聚集索引扫描,执行exec sp_lock查看申请的锁:

spid dbid ObjId IndId Type Resource Mode Status
58 17 610361489 0 TAB   IS GRANT
58 17 610361489 1 PAG 1:8086440                        S GRANT
58 17 610361489 1 PAG 4:459840                         S GRANT
58 17 610361489 1 PAG 4:167476                         S GRANT
58 17 610361489 1 PAG 1:8317404                        S GRANT
58 17 610361489 1 PAG 1:8432309                        S GRANT
58 17 610361489 1 PAG 1:8154231                        S GRANT
58 17 610361489 1 PAG 1:8267887                        S GRANT
58 17 610361489 1 PAG 1:8052942                        S GRANT
58 17 610361489 1 PAG 1:8086441                        S GRANT
58 17 610361489 1 PAG 4:459841                         S GRANT
58 17 610361489 1 PAG 4:167477                         S GRANT
58 17 610361489 1 PAG 1:8317405                        S GRANT
58 17 610361489 1 PAG 1:8432308                        S GRANT
58 17 610361489 1 PAG 1:8154230                        S GRANT
58 17 610361489 1 PAG 1:8267886                        S GRANT
........              

此处省略数万行

因为使用的是聚集索引扫描,表中的每一行都会读取到,如果还是按上面的规则的话,对每一行都加锁,那会产生大量的锁,所以SQL SERVER默认对锁进行了升级,直接在PAGE上加了S锁,如果页中的数据被修改(插入或修改页中的一行数据),会在页上加IX锁,而S和IX是不兼容的,所以在PAGE上的S锁就能达到隔离级别的要求

所以,通过索引扫描来获取数据的查询,大致总结如下:

1、对扫描到的每一个PAGE加上S锁。

S锁和IS锁的释放时间是:

1、当事务隔离级别为read committed时,当读取完这一行或页时(此时查询还没有结束),直接释放。

2、当事务隔离级别为repeatable read时,如果读取的这一行不满足查询条件,会直接释放掉,如果满足条件,会等到事务结束再释放,而通过扫描对页加的S锁,会等到事务结束才释放

锁的申请和释放可以通过Sql server profile中跟踪:Lock:Acquired,Lock:Released来获得:

时间: 05-05

sql server中select语句需要申请的锁的相关文章

SQL Server中DML语句要申请的锁

对于select语句: 1.当采用表扫描时,会直接锁定page,而不是锁定具体的某条记录,所以会有这些锁: A.数据库S锁 B.表的IS锁 C.页的S锁 2.当采用索引来查找数据时,会锁定具体的记录,所以会有这些锁: A.数据库S锁 B.索引中page的IS锁 C.索引中page中的key的S锁 D.表的IS锁 E.页的IS锁 F.RID的S锁 3.对于读过的页面,会加一个IS锁. 对于使用的索引,会对key加上S锁,对索引key所在的页面会加上IS锁. 在查询过程中,会对每一条读到的记录或ke

SQL Server 中SELECT INTO 和 INSERT INTO SELECT 两种表复制语句

1.INSERT INTO SELECT语句 语句形式为:Insert into Table2(field1,field2,...) select value1,value2,... from Table1 要求目标表Table2必须存在,由于目标表Table2已经存在,所以我们除了插入源表Table1的字段外,还可以插入常量. 2.SELECT INTO FROM语句 语句形式为:SELECT vale1, value2 into Table2 from Table1 要求目标表Table2不

SQL Server 基本SELECT语句

1.SELECT 和 FROM 语句 SELECT表示执行的是查询,接着需要更知道从哪边查询数据,FROM就是限制读取的数据在哪一个表或哪几个表中,这样就构成了一个基本语句. SELECT * FROM [表的名字] *的作用就是选择表中的所有列 一些细节:SELECT和FROM都是大写,但并不是规定一定大写,习惯写成大写增加可读性,表名列名变量名可大小写混写,但必须保持一致! 另一些小示例:为了加快查询速度 最好不要使用*,而是用多少数据查询多少数据! 2.WHERE语句 WHERE语句用来设

SQL Server中CURD语句的锁流程分析

我只在数据库选项已开启“行版本控制的已提交读”(READ_COMMITTED_SNAPSHOT为ON)中进行了观察. 因此只适用于这种环境的数据库. 该类数据库支持四种不同事务隔离级别,下面分别观察数据库的锁行为,测试代码未涉及锁升级. 请先参阅: 数据库引擎中的锁定 https://msdn.microsoft.com/zh-cn/library/ms190615.aspx 一.环境:数据库开启“行版本控制的已提交读”,要求单一连接(非单用户模式) http://gf.gamebbs.qq.c

SQL Server中Delete语句表名不能用别名

delete from TABLEA A where A.FIELD1=10        (ORACLE适用)delete TABLEA from TABLEA A where A.FIELD1=10 (SQLSERVER适用)delete  from TABLEA where TABLEA.FIELD1=10    (Ora/SQL均适用)

sql server中的go

1. 作用:向 SQL Server 实用工具发出一批 Transact-SQL 语句结束的信号.2. 语法:一批 Transact-SQL 语句GO如Select 1Select 2Select 3GO3. 说明:1) GO 不是 Transact-SQL 语句:2) 它是 sqlcmd 和 osql 实用工具以及 SQL Server Management Studio 代码编辑器识别的命令.3) SQL Server 应用程序可以将多个 Transact-SQL 语句作为一个批发送到 SQ

为什么SQL语句Where 1=1 and在SQL Server中不影响性能

    最近一个朋友和我探讨关于Where 1=1 and这种形式的语句会不会影响性能.最后结论是不影响.     虽然结论正确,但对问题的认识却远远没有解决问题的根本.实际上在T-SQL语句的书写过程中经常犯得错误就是得出一个很窄的结论,然后教条式的奉若圣经,对于T-SQL领域来说,在网上经常可以看到所谓的优化守则,随便在网上搜了一些摘录如下: 不要有超过5个以上的表连接(JOIN) 考虑使用临时表或表变量存放中间结果 少用子查询 视图嵌套不要过深,一般视图嵌套不要超过2个为宜. 对出现在wh

SQL Server中存储过程 比 直接运行SQL语句慢的原因

问题是存储过程的Parameter sniffing 在很多的资料中都描述说SQLSERVER的存储过程较普通的SQL语句有以下优点: 1. 存储过程只在创造时进行编译即可,以后每次执行存储过程都不需再重新编译,而我们通常使用的SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度. 2. 经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作.当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete时),可将此复杂操作用

SQL Server中存储过程比直接运行SQL语句慢的原因

原文:SQL Server中存储过程比直接运行SQL语句慢的原因 在很多的资料中都描述说SQLSERVER的存储过程较普通的SQL语句有以下优点: 1.       存储过程只在创造时进行编译即可,以后每次执行存储过程都不需再重新编译,而我们通常使用的SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度. 2.       经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作.当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query