我遇到了SQL Server 2012中的经典Parameter Sniffing问题。基于一些研究,我发现了围绕这个问题的多种选择。我需要了解两者之间的区别是OPTION(OPTIMIZE FOR UNKNOWN)
与OPTION(RECOMPILE)
。
我在我遇到此问题的查询结束时使用OPTION(RECOMPILE)
时犹豫不决,因为它会强制服务器每次都生成一个新的执行计划。如果我经常调用此查询,这将会占用该计算机的CPU。
因此,我使用他最好的解决方案,这两个选项之间的真正区别是什么?
OPTION(OPTIMIZE FOR UNKNOWN)
会重用缓存而不是每次重新编译吗?
答案 0 :(得分:10)
OPTION(OPTIMIZE FOR UNKNOWN)
将重用缓存而不是重新编译 每一次?
是的,它会。
OPTION(OPTIMIZE FOR UNKNOWN)
与OPTION(RECOMPILE)
之间存在两个主要差异,可以从MSDN的引用中看出:
OPTIMIZE FOR UNKNOWN
指示查询优化器使用统计信息 数据而不是所有局部变量的初始值时 查询已编译和优化,包括使用创建的参数 强制参数化。
RECOMPILE
指示SQL Server数据库引擎放弃该计划 执行后为查询生成,强制查询优化器 在下次执行相同查询时重新编译查询计划。 如果不指定
RECOMPILE
,数据库引擎会缓存查询计划 并重复使用它们。编译查询计划时,RECOMPILE
查询提示 使用查询中任何局部变量的当前值,如果 查询在存储过程内,传递给当前值 任何参数。
因此,两个主要区别是:
通常会生成并重用生成的查询计划。 OPTIMIZE FOR UNKNOWN
不会影响引擎的此功能。 RECOMPILE
禁止此功能并告诉引擎放弃计划而不将其放入缓存中。
通常是优化者"嗅探"参数值并在生成计划时使用这些值。 OPTIMIZE FOR UNKNOWN
抑制此功能并告诉引擎将所有参数视为其值未知。优化程序具有内置规则和启发式,如何使用可用的统计信息来处理各种过滤条件。有关详细信息,请参阅Optimize for… Mediocre?。通常,参数嗅探在第一次运行查询/存储过程时使用,并在第一次运行期间使用参数值。生成的计划被缓存,以后可以重复使用。
这里要记住的一个非显而易见的事情是,在这两种情况下(正常时没有任何查询提示和OPTIMIZE FOR UNKNOWN
提示)生成的计划必须有效并为任何可能的参数值。它适用于在正常/无提示情况下第一次运行期间使用的嗅探值;它不是针对OPTIMIZE FOR UNKNOWN
情况中的任何特定值定制的,但如果参数稍后以任何方式更改,它仍然有效。
这很重要,它会阻止优化程序执行某些转换和简化计划。
OPTION(RECOMPILE)
允许优化器在每次运行期间内联参数的实际值,优化器使用参数的实际值来生成更好的计划。它不必担心生成的计划可能无法与其他参数值一起使用,因为该计划不会被缓存和重用。
此效果对于Dynamic Search Conditions查询几乎可见。例如:
SELECT ...
FROM T
WHERE
(@ParamSomeID = 0)
OR
(
@ParamSomeID = -1
AND
T.SomeID NOT IN
(
SELECT OtherTable.SomeID
FROM OtherTable
)
)
OR
(
T.SomeID IN
(
SELECT OtherTable.SomeID
FROM OtherTable
WHERE OtherTable.SomeID = @ParamSomeID
)
)
OPTION(RECOMPILE)
如果@ParamSomeID
为0
,优化程序会将查询视为根本没有任何WHERE
子句。该计划根本不会提到OtherTable
。
如果@ParamSomeID
为-1
,则该计划会使用Left Anti Semi Join将T
加入OtherTable
并扫描整个OtherTable
。
如果@ParamSomeID
是5,则该计划会在OtherTable
上的唯一索引中执行索引搜索,并且只读取OtherTable
中的一行。
如果没有OPTION(RECOMPILE)
,就不会发生这种简化和转换。
使用OPTION(RECOMPILE)
的另一个原因是您的数据分布非常偏差。例如,您有一个包含1M行的表。一列在990K行中具有值0,在1K行中具有从1到10的值。过滤此列的查询应具有不同的计划,具体取决于过滤器的实际值。
在上述两个示例中,OPTIMIZE FOR UNKNOWN
都会产生一个平庸的计划。
答案 1 :(得分:8)
OPTION(OPTIMIZE FOR UNKNOWN)是否会重用缓存而不是每次重新编译?
是。优化未知将影响计划的生成方式(即明确阻止它嗅探参数并将其与列数据直方图进行比较),但一旦生成,计划将保留在缓存中并重复使用。
OPTION(RECOMPILE)
将强制重新编译每次执行,并且是一种相当沉重的方法。只有在每个查询可能不同,复杂且可能具有大量运行时的分析DW / BI环境中才有意义。
您还可以使用其他选项:
这两种方法都可以让您获得与帖子相同的效果,但是以非侵入性的方式(没有应用代码/查询更改)。
答案 2 :(得分:2)
我用过两者。 OPTION(OPTIMIZE FOR UNKNOWN)
用于获取各种参数的重型搜索存储过程。有一些条件,我不知道(统计数据和什么不是),会抛出优化,查询是平凡的,但是,它会导致严重的延迟(甚至超时)。 OPTION(OPTIMIZE FOR UNKNOWN)
解决了这个问题,但并不理想。
同样繁重的搜索程序会产生间歇性问题,这意味着几个月后搜索会超时。直接的解决方案是调用sp_recompile
,这是向存储过程添加OPTION(RECOMPILE)
子句的同义词。
当您键入" 解决方案时,存储过程的内容推动了"结果,其中每三次击键将触发数据库搜索,结果将填充到下拉列表中。
最后,我删除了OPTION(OPTIMIZE FOR UNKNOWN)
,只是在我的夜间维护工作中添加了EXEC sp_recompile<sp>
,这解决了所有问题。