视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
sqlserver中select语句需要申请的锁
2020-11-09 16:29:44 责编:小采
文档


以NA_TrafficMemberOrderRelation表为例,表的索引如下: index_id name cols 1 PK__NA_Traff__FB675129A903 TrafficMemberOrderRelationId 26 IX_NA_TrafficMemberOrderRelation_usermobile UserMobile 下面的查询语句,正常情况下会先使用IX_NA_TrafficM

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

index_id name cols
1 PK__NA_Traff__FB675129A903 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__FB675129A903) where usermobile='13719805324' and ecprdcode='50615801625'

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

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

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

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

58 17 6103614 0 TAB IS GRANT

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

58 17 6103614 26 PAG 4:53295 IS GRANT

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

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

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

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

1、对使用到的PAGE加IS锁

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


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

select * from NA_TrafficMemberOrderRelation where CreateTime='2015-10-25 05:29:47.000'
CreateTime字段没有索引,所以上面的查询会使用聚集索引扫描,执行exec sp_lock查看申请的锁:

spid dbid ObjId IndId Type Resource Mode Status
58 17 6103614 0 TAB IS GRANT
58 17 6103614 1 PAG 1:80840 S GRANT
58 17 6103614 1 PAG 4:459840 S GRANT
58 17 6103614 1 PAG 4:167476 S GRANT
58 17 6103614 1 PAG 1:8317404 S GRANT
58 17 6103614 1 PAG 1:8432309 S GRANT
58 17 6103614 1 PAG 1:8154231 S GRANT
58 17 6103614 1 PAG 1:8267887 S GRANT
58 17 6103614 1 PAG 1:8052942 S GRANT
58 17 6103614 1 PAG 1:80841 S GRANT
58 17 6103614 1 PAG 4:459841 S GRANT
58 17 6103614 1 PAG 4:167477 S GRANT
58 17 6103614 1 PAG 1:8317405 S GRANT
58 17 6103614 1 PAG 1:8432308 S GRANT
58 17 6103614 1 PAG 1:8154230 S GRANT
58 17 6103614 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来获得:

下载本文
显示全文
专题