在谈谈SQL Server的锁机制之前来思考以下这个场景当你在酷暑的时候骑着自己的小车往目的地行走时路上连续遇到几个时间很长的红灯是不是很郁闷?有时候 你可能实在受不了闯了个红灯其实在大部分情况下问题不大如果通行的汽车很多那就不好说了因为不遵守规则的人太多都为了达到目的去走捷径不愿意等 待这样才有了交警交警的作用就是维护这些红绿灯的规则这些红绿灯就像锁一样锁住或延长你去目的地的时间但是如果没有交警大家又不自由遵守红绿灯 规则会导致什么呢?大家想想都知道
这个系列的一篇文章中提供的事务管理器中有个锁管理器就是这里的交警它维护着SQLServer中的锁前段提到的大部分情况指的就是在系统事务 量不大的时候这时候的锁永远不会是什么大问题除非你知道你的系统永远就给几个人用否则考虑到避免系统以后的并发量上升引起数据安全与效率问题那你 得深入了解锁机制在研究锁之前假定你已经了解事务的ACID概念它是整个SQL Server的精髓所在如果没有事务那就不用谈锁了除了事务需要锁以外其他任何东西都需要这个让SQL不自由的机制说到底锁是一个平衡并发与数据安 全的机制如果没有锁任何SQL都能覆盖其他SQL执行的数据那么数据会出现不一致的情况如果锁得太狠那将影响数据库系统的并发性以及效率(包括 锁本身带来的额外开销)这时候就需要去权衡SQLServer锁管理器就充当权衡这两者关系的角色如下图所示
SQL Server中锁的知识点实在太多比如锁从模式上分为共享锁(S)更新锁(U)排他锁(X)架构锁(SchSSchM)意向锁(IS IUIX)转换锁(SIXSIUUIX)大容量更新锁(BU)锁从粒度上分为数据库锁文件锁表锁堆锁索引锁页锁键锁区锁行 锁应用程序锁元数据锁锁之间存在兼容性问题锁会根据情况进行升级锁控制不好会出现死锁悲观锁的隔离性未提交读已提交读可重复读可序列 化乐观锁的隔离性读提交快照隔离快照隔离闩(shuan)锁随便列下就一大堆问题要说清楚需要花很大篇幅还是抱着与前几篇文章的风格仔 细分析一个具体的问题——锁升级
准备
有一个动态管理视图可以查看所有锁sysdm_tran_locks还有一个动态管理视图可以查看哪些请求正在阻塞其他的请求sysdm_os_waiting_tasks
什么是锁升级
锁升级是指锁的粒度由细向粗转换如由行锁转成表锁
需要锁升级吗?
一般来说锁的粒度越小并发性越好但是如果去锁定的东西多就需要的锁越多这样会消耗SQLServer的cpu与内存一个锁占用内存约为 字节你算算如果用行锁去锁定百万千万的表需要多少内存而且管理锁(创建锁维护锁销毁锁等)也是有代价的会消耗cpu 如果用一个大点的锁就将这些百万千万的锁合并成一个锁了管理起来也方便消耗资源也小
什么时候出现锁升级
SQLServer意识到锁定的页面或行数过大的时候发生怎么意识到过大呢?由两种方法识别请求用于的锁的数目超过锁数目临界值锁管理器为单 独一个查询消耗过多的内存超过内存临界值有其他一个超过临界值SQLServer就会试图升级注意这里说的锁数据以及内存是值由同一个查询发生的 而不是总共的这里说的临界值并不是固定的SQLServer采用启发式算法去动态调整
控制锁升级
SQLServer提供一些可以让我们控制锁升级的入口在SQLServer中可以通过
alter table test
set (lock_escalation = auto|table|disable)
我们还可以通过在代码中显示指定pagelocktablock提示会强制SQLServer使用更粗的锁不过这个设置不合理的话会导致并发降低建议一般情况下不用除非你很清楚这样带来的影响
举例说明
建库建表
create database Test
create table test
(
ID identity() primary key
[Name] varchar() not null default ‘’
CreatedTime datetime not null default getdate();
)
查看当前锁情况
默认某个连接对整个数据库有个共享锁
循环插入几十万条记录
while =
insert into test(Name) values (‘kk’)
插入时的锁快照
从上图中看出这个快照中有三个数据库共享锁一个页级意向排他锁一个表级意向排他锁两个行级排他锁
三个数据库共享锁前面已经提过默认某个连接对整个数据库有个共享锁
一个页级意向排他锁一个表级意向排他锁在页以及表级表示资源的一部分实际已经有锁进行保护这样的好处允许其他请求锁在表页级别上进行检查减 少不必要的更细的锁请求提高性能比如在这种情况下如果允许alter操作那么这个操作就会等待因为这里有表级排他锁它提示alter操作该表有活 动
跟蹤Lock:Escalation事件
在profiler中设置只跟蹤Lock:Escalation事件锁升级事件
更新表中记录
update test set name = ‘name’ where name = ‘kk’
在profiler中看到了Lock:Escalation事件被触发
更新时的快照为(按顺序)
如上图此时update操作以排他锁定它更新的行
如上图此时update操作以排他锁锁定了整个表以架构稳定锁(SchS)锁定它相关的元数据表
如上图此时释放了对元数据表的架构稳定锁(SchS)锁剩下对整个表的排他锁
从上面的分析中发现SQLServer锁机制是有点复杂的不过也是很有意思的研究后你会发现它真的很智能今天分析就到此结束文中如有描述不当的地方欢迎指出共同进步才是硬道理(来源博客园)