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