[译]SQL Passion Week 10: 计划缓存

Week 9: Plan Caching

 
Adhoc SQL Statements
 
每次我们向SQL Server提交一个特定的SQL语句时, 查询计划为每一个unique query编译. 什么叫做unique query? 非常简单. SQL Server为完整的SQL语句(包含Hard-coded的值)产生一个Hash值, 作为一个查找值在计划缓存中使用. 如果找到该hash值,再该计划被复用. 否则将会编译一个新的计划, 所以想象一下现在执行下面3个查询
 
SELECT * FROM Sales.SalesOrderHeader
WHERE CustomerID = 11000
GO
SELECT * FROM Sales.SalesOrderHeader
WHERE CustomerID = 30052
GO
SELECT * FROM Sales.SalesOrderHeader
WHERE CustomerID = 11223
GO

这三个查询将会编译成不同的查询计划, 因为包含了一个hard-coded的参数值. 因此, 这三个查询计划都被放进了缓存中, 我们称之为 缓存污染.

因为Hard-coded的原因, 这些查询计划很难被重用, 浪费了宝贵的缓存空间.

Plan Stability
 
当我们为查询语句或存储过程指定一个参数值执行, 可以轻易的套用计划复用, 但同时也可能会引发一个性能问题: 当某个查询计划实行一个Bookmark Lookup查找时(非聚集索引没有覆盖到查询), 如同week8讲过的,  如果只是检索少量数据,Bookmark Lookup是说的通的. 加入超过了临界点, 会比全表/索引扫描更有效率.
 
但是一旦重用查询计划, 这些就不在考量之内(是否达到临界点), SQL Server会盲目信任重用的计划, 不管性能将会慢到何种地步.
 
看下面的实际查询计划
 
在这里,SQL Server盲目的复用了查询计划, 如图所示, 预测返回的行数和实际返回行数有着很大的差异. 缓存里的计划, 是基于假设查询只返回少量的记录, 但实际上返回了1499行. 我们在缓存中找到的是基于返回少量记录而做优化的计划.
 
引发这些的根源在于我们没有一个计划稳定性, 基于估计的返回记录数, 我们得到的是Bookmark Lookup或者Table/Cluster Scan. 这是最常见的性能问题.
 
解决这个问题的方法就是,通过包含索引来避免Bookmark Lookup, 不管参数如何变化, 得到的是同样的查询计划, 同样的查询性能.
 
 
 
原文地址:https://www.cnblogs.com/alphaqcode/p/5311724.html