我在同一个 SQL Server 2005 实例上运行了两个几乎相同的查询:
- 第一个是
SELECT
LINQ 生成的原始查询(我知道,我知道......我不是应用程序开发人员,只是 DBA :)。 - 第二个和第一个完全一样,
OPTION (RECOMPILE)
最后加了一个。
没有其他任何改变。
第一个每次运行需要 55 秒。
第二个需要 2 秒。
两个结果集是相同的。
为什么这个提示会在性能上产生如此巨大的提升?
Books Online 上的条目RECOMPILE
没有提供非常详细的解释:
指示 SQL Server 数据库引擎在查询执行后放弃为查询生成的计划,强制查询优化器在下次执行相同查询时重新编译查询计划。如果不指定 RECOMPILE,数据库引擎会缓存查询计划并重用它们。编译查询计划时,RECOMPILE 查询提示使用查询中任何局部变量的当前值,如果查询在存储过程中,则将当前值传递给任何参数。
RECOMPILE 是创建使用 WITH RECOMPILE 子句的存储过程的有用替代方法,当必须重新编译存储过程中的查询子集而不是整个存储过程时。有关详细信息,请参阅重新编译存储过程。当您创建计划指南时,重新编译也很有用。有关更多信息,请参阅使用计划指南优化已部署应用程序中的查询。
OPTION (RECOMPILE)
由于我的查询有很多局部变量,我的猜测是当我使用查询提示时,SQL Server 能够(认真地)优化它。
我所看到的每一个地方,人们都在说OPTION (RECOMPILE)
应该避免这种情况。对此的解释通常是使用这个提示 SQL Server 无法重用这个执行计划,因此每次都要浪费时间重新编译它。
(但是)鉴于巨大的性能优势,我倾向于认为这次使用此查询提示将是一件好事。
我应该使用它吗?如果没有,有没有一种方法可以强制 SQL Server 使用更好的执行计划而无需此提示且无需更改应用程序?
如Microsoft SQL Server 2005 中查询优化器使用的统计信息一文中所述
当优化器对一列根本没有可用的统计信息时,它会猜测谓词
=
将匹配 10% 的行、BETWEEN
9% 和任何一个>, >=, < and <=
将匹配 30%。如果有可用的列统计信息,则=
谓词将被区别对待,如下所示。所以这本质上与使用 for 相同
OPTIMIZE FOR (UNKNOWN)
。它可能比简单的10%
猜测更准确,但它不是针对您查询的特定值量身定制的。使用
RECOMPILE
您可能会获得更准确的基数估计,因此具有连接顺序/连接类型的不同计划更适合从实际查询的不同部分返回的行数。