锁升级与执行计划状况

锁升级(Lock Escalations)很是很是很差,由于最后你会是在表级别有排它或共享锁。在表级别放上这样的限制锁会下降你的并发和数据库的吞吐量。html

今天我不想讨论锁升级的基本信息,今天我想详细谈下当锁升级触发时,SQL Server的这种锁行为对执行计划状况的影响。sql

筛选器(Filter)运算符——你的敌人!

假设咱们有以下很是简单的查询:数据库

1 SELECT * FROM Sales.SalesOrderDetail
2 WHERE ModifiedDate > '20200501'
3 GO

如你所见,我就从Sales.SalesOrderDetail表请求ModifiedDate晚于2020年5月1日的记录。固然,这个查询不会返回任何记录,由于选择的日期是未来的。性能优化

但当你查看执行计划时,你会看到查询优化器选择了完整的汇集索引扫描运算符,紧接着是筛选运算符。并发

在执行计划里,一个完整的汇集索引扫描运算符,紧接着是一个筛选器运算符真的是一个很差的模式。它意味着一开始(在扫描运算符),你就读取大量的数据,接下来(在筛选器运算符)你剔除不符合的数据。物理上你读取的记录数比你逻辑请求的数多不少。在这个例子里,我从Sales.SalesOrderDetail表读取了121317条记录,但没有1条记录符合个人查询谓语(基于ModifiedDate列)。所以全部列在筛选器运算符被剔除。性能

如今假设你在像可重复读(Repeatable Read)这样更多限制的事务隔离级别运行这个查询。在这个状况下,SQL Server必须把持共享锁直到事务结束。也就是说,当你读取超过5000条记录时,在汇集索引扫描期间,SQL Server会触发锁升级。这会很糟糕,由于过后读取的不符合的数据会在筛选器剔除。你啥也没作就触发了锁升级。优化

剩余谓语(Residual Predicate)——你的朋友!

你必须接受筛选器运算符很是很差。但咱们能够作的更好么?固然,由于SQL Server也支持所谓的剩余谓语(Residual Predicate):当记录从数据页读取时,这个谓语会“直接”在存储引擎内部评估。当谓语知足时,行是在存储引擎外传入执行计划。若是谓语不知足,行会忽略并消失。在执行计划里,它不会移交给下个运算符。spa

这个和筛选器运算符彻底不一样!使用剩余谓语,你只处理在执行计划里逻辑请求的行(你仍是要读取请求的数据页……)。当基于剩余谓语没有符合的行时,没有行在执行计划里运输。咱们来看下面的查询。scala

1 SELECT * FROM Person.Person WITH (INDEX(1))
2 WHERE ModifiedDate > '20200501'
3 GO

这里我从Person.Person表请求行,一样对于选择的查询谓语没有行返回。但此次SQL Server能把查询谓语以剩余谓语的方式压入存储引擎。所以查询谓语在存储引擎里直接评估:code

当你在可重复读(Repeatable Read)事务隔离级别里运行这个查询时,你不会再触发锁升级,由于在执行计划里你不处理任何行——在存储引擎里它们就被或略了。所以对于查询,你是否会触发锁升级取决与你的执行计划状况……

小结

如你在这篇文章里所见,执行计划状况会大大影响SQL Server的锁行为。剩余谓语就像帅选器运算符,但它是在存储引擎里,从数据页读取行后,直接评估。它是SQL Server雇佣的性能优化者。

在一些状况下,查询优化器能够把查询谓语做为剩余谓语压入存储引擎,但在一些状况下作不到,查询优化器只能引入筛选器运算符。不要问我什么状况是能够的,什么状况是不能够的。这个行为微软也没有文档说明……

感谢关注!

参考文章:

http://www.sqlpassion.at/archive/2016/02/29/lock-escalations-and-execution-plan-shapes/

相关文章
相关标签/搜索