我最近处理了一个有问题的存储过程。有时,跑得非常快,有时,跑得非常非常长。我确定错误的参数嗅探是原因。
仅供参考 - proc 中的参数是日期时间,查询使用这些参数来搜索日期范围。
无论如何,这就是我尝试的:
- 重新创建过程并使用
WITH RECOMPILE
- 没有帮助 - 重新创建过程并添加
OPTION (RECOMPILE)
- 没有帮助 - 重新创建过程并添加
OPTION (OPTIMIZE FOR UNKNOWN)
- 运行速度快 - 重新创建 proc 并使用局部变量 - 运行速度快
为了帮助我理解....使用局部变量和OPTIMIZE FOR UNKNOWN
使用平均密度统计数据来制定计划的方式完全相同吗?
我也尝试了几种组合:
- 重新创建 proc 并添加
OPTIMIZE FOR UNKNOWN
&OPTION (RECOMPILE)
- 运行速度快 - 使用局部变量重新创建过程&
OPTION (RECOMPILE)
- 运行缓慢
我已经阅读了使用的潜在危险,OPTIMIZE FOR UNKNOWN
并且在很多情况下,使用局部变量被提出来就好像它是同一件事一样。这就是让我认为这是同一件事的原因。
但是 - 我如何解释尝试 6 运行缓慢。
我想说是的,统计数据已更新,但它的采样率小于零 - 表格非常大 +- 16 亿行。
可能还值得注意 - 我sp_blitzcache
在特定过程上使用了 awesome 和 filtered - 有一个编译超时警告 - 我的直觉告诉我这里需要注意。
OPTIMIZE FOR UNKNOWN 和局部变量(稍后会详细介绍)都使用统计数据的平均值来确定行数。参数嗅探正在追踪特定值以获得特定行数,从而导致您所看到的不同计划。RECOMPILE 只是强迫它追求不同的特定值。在某些情况下,这是正确的答案。OPTIMIZE FOR 值也变得具体。
这都是由环境驱动的。有时基于平均值的通用计划会更好。其他时候,一个特定的计划会更好(OPTIMIZE FOR)。还有一些时候,您不能也不会知道什么最有效,因此 RECOMPILE 成为您的朋友(尽管它引入了其他痛苦)。
现在,我承诺更多关于局部变量的内容。需要知道的一件事是,在编译时,该值是未知的,因此,就像 OPTIMIZE FOR UNKNOWN 一样,您将获得平均值。但是,语句级重新编译实际上会知道局部变量的值是多少,如果您处于需要该平均值的情况下,您会看到生成了错误的计划。所以,一般来说,我不建议使用局部变量,而是坚持使用 OPTIMIZE FOR UNKNOWN。
此外,Query Store 和 Plan Forcing 是处理不良参数嗅探的好方法,无需处理代码。只是说。