锁升级阈值
如果没有使用 ALTER TABLE SET LOCK_ESCALATION 选项来禁用表的锁升级并且满足以下任一条件时,则将触发锁升级:
如果由于锁冲突导致无法升级锁,则数据库引擎每当获取 1,250 个新锁时便会触发锁升级。
当 Transact-SQL 语句在单个表或索引的引用上获取至少 5,000 个锁时,或在表已分区的情况下,在单个表分区或索引分区的引用上获取至少 5,000 个锁时,会触发锁升级。例如,如果该语句在一个索引上获取 3,000 个锁,在同一表中的另一个索引上获取 3,000 个锁,这种情况下不会触发锁升级。同样,如果语句中含有表的自联接,并且表的每一个引用仅在表中获取 3,000 个锁,则不会触发锁升级。
只有触发升级时已经访问的表才会发生锁升级。假定某个 SELECT 语句是一个按 TableA、TableB 和 TableC 的顺序访问三个表的联接。该语句在 TableA 的聚集索引中获取 3,000 个行锁,在 TableB 的聚集索引中获取至少 5,000 个行锁,但是仍无法访问 TableC。当数据库引擎检测到该语句在 TableB 中获取至少 5,000 个行锁时,会尝试升级当前事务在 TableB 中持有的所有锁。它还会尝试升级当前事务在 TableA 中持有的所有锁,但是由于 TableA 中锁的数量 < 5000,因此,升级无法成功。但它不会尝试在 TableC 中进行锁升级,因为发生升级时尚未访问该表。
每当锁的数量大于锁升级的内存阈值时,数据库引擎都会触发锁升级。内存阈值取决于 locks 配置选项的设置:
数据库引擎可以为升级选择任何会话中的活动语句,而且,只要实例中使用的锁内存保持在阈值之上,每获取 1,250 个新锁,它就会为升级选择语句。
升级混合锁类型
发生锁升级时,为堆或索引选择的锁必须足够强,才能满足限制性最强的较低级别的锁的要求。
例如,假定会话执行下列操作:
UPDATE 语句将获取下列锁:
SELECT 语句将获取下列锁:
如果 SELECT 获取了触发锁升级的足够锁并且升级成功,表上的 IX 锁将被转换为 X 锁,而所有行、页和索引锁都将被释放。更新和读取操作都受表上的 X 锁保护。
减少锁定和升级
在大多数情况下,数据库引擎使用默认的锁定和锁升级设置进行操作时提供的性能最佳。如果数据库引擎实例生成大量锁并且频繁进行锁升级,请考虑通过下列方法减少锁定:
注意:
更改隔离级别会影响数据库引擎实例上的所有表。
还可以使用跟踪标志 1211 和 1224 来禁用所有或某些锁升级。有关详细信息,请参阅跟踪标志 (Transact-SQL)。此外,还可以使用 SQL Server Profiler Lock:Escalation 事件监视锁升级