SQL Server 使用锁管理器跟踪数据库对象是否被锁住。通常一个查询将锁住一行或者一页,当锁超过一定范围之后,SQL Server 尝试将锁升级为表锁来保证对内存的使用。锁升级有时会导致堵塞或者死锁。在 SQL Server Profiler 中我们可以用 [Lock:Escalation] 事件来跟踪锁的升级。
什么是锁升级?
锁升级是将许多细粒度锁(如行锁/页锁)转换为表锁的过程。Microsoft SQL Server 动态确定何时执行锁升级。
一般来说,维护锁需要内存资源。SQL Server 默认使用行级锁,但是对于 SQL 引擎来说,将大量的行锁转换为单个表锁,并在进程中释放行锁所持有的内存更为优化。
锁升级是 SQL Server 使用的一种优化技术,是处理大型更新锁定的方式。当 SQL Server 将要修改大量行时,数据库引擎使用更少、更大的锁(表锁)比处理大量单个锁(行锁)更有效。
SQL Server 中的锁层次结构为:
数据库 –> 表 –> 页面 –> 行
什么是锁升级阈值?
根据 MSDN 文档,当 T-SQL 语句在表的单个引用上获得至少 5000 个锁时,会触发锁升级。虽然数据库引擎在每 1250 个新获取的锁上检查可能的升级,但当且仅当 T-SQL 语句在表的单个引用上获取至少 5000 个锁时,才会发生锁升级。
锁升级模式是什么?
数据库的锁升级模式,你可以检查数据库中表的锁升级模式:
select name, lock_escalation_desc from sys.tables
AUTO | 此选项允许 SQL Server 数据库引擎选择适合于表架构的锁升级粒度;(AUTO:如表已分区,将使用分区的hobt锁,但并发情况增加)如果该表已分区,则允许将锁升级到分区。锁升级到分区级别之后,该锁以后将不会升级到 TABLE 粒度;如果该表未分区,则会将锁升级到 TABLE 粒度。 |
TABLE | 无论表是否已分区,都会在表级粒度完成锁升级。默认值为 TABLE |
DISABLE | 在大多数情况下禁止锁升级。表级别的锁未完全禁止;例如,当扫描在可序列化隔离级别下没有聚集索引的表时,数据库引擎必须使用表锁来保证数据的完整性。 |
更改表的锁模式,可以使用以下SQL:
ALTER TABLE SET (LOCK_ECALATION = AUTO | TABLE | DISABLE)
如何防止锁升级?
你可以通过遵循以下 3 个良好做法来减少锁定问题:
- 缩短事务时间。
- 通过进行性能调整并提高它们的效率来减少昂贵查询的锁占用。
- 将大操作分批执行。
在 SQL Server 2005 中,可以使用跟踪标志 1211 来禁用整个实例中的锁升级。而在 SQL Server 2008 中,可以使用新的选择来禁止某个表的锁升级。当然,禁用锁升级可能不是最佳选择,你可能会遇到高内存消耗问题。