参数嗅探 - 提示和修复

Sic*_*orf 4 sql-server parameter-sniffing query-performance

我最近处理了一个有问题的存储过程。有时,跑得非常快,有时,跑得非常非常长。我确定错误的参数嗅探是原因。

仅供参考 - 过程中的参数是日期时间,查询使用这些参数来搜索日期范围。

无论如何,这就是我的尝试:

  1. 重新创建过程并使用 WITH RECOMPILE- 没有帮助
  2. 重新创建过程并添加OPTION (RECOMPILE)- 没有帮助
  3. 重新创建了过程并添加了OPTION (OPTIMIZE FOR UNKNOWN)- 运行速度快
  4. 重新创建了过程并使用了局部变量 - 运行速度快

为了帮助我理解......使用局部变量和OPTIMIZE FOR UNKNOWN使用平均密度统计数据来制定计划的方式完全相同吗?

我也尝试了几种组合:

  1. 重新创建了过程并添加了OPTIMIZE FOR UNKNOWN & OPTION (RECOMPILE) - 运行速度快
  2. 使用局部变量重新创建了过程& OPTION (RECOMPILE) - 运行缓慢

我已经了解了使用的潜在危险OPTIMIZE FOR UNKNOWN,并且在很多情况下,使用局部变量被提出来,就好像它是同一件事一样。这让我认为这是同一件事。

但是 - 我该如何解释尝试 6 运行缓慢。

我想说的是,是的,统计数据已更新,但采样率低于 0% - 表很大 +- 16 亿行。

可能还值得注意 - 我使用了 Awesomesp_blitzcache并在特定过程上进行了过滤 - 它有一个编译超时警告 - 我的直觉告诉我这是这里需要注意的事情。

Gra*_*hey 5

OPTIMIZE FOR UNKNOWN 和局部变量(稍后会详细介绍)都使用统计数据中的平均值来确定行计数。参数嗅探是根据特定值来获取特定行数,从而产生您所看到的不同计划。RECOMPILE 只是强制它追求不同的特定值。在某些情况下,这是正确的答案。OPTIMIZE FOR 值也变得具体。

这都是由环境驱动的。有时基于平均值的通用计划会更好。其他时候,一个特定的计划会更好(优化)。还有一些时候,您不能也不会知道什么最有效,因此 RECOMPILE 成为您的朋友(尽管它会带来其他痛​​苦)。

现在,我承诺更多关于局部变量的内容。需要知道的一件事是,在编译时,该值是未知的,因此,就像“针对未知进行优化”一样,您将获得平均值。但是,语句级重新编译实际上会知道局部变量的值是什么,并且如果您处于需要该平均值的情况,您可能会看到生成的错误计划。因此,一般来说,我不建议使用局部变量,而是坚持使用 OPTIMIZE FOR UNKNOWN。

此外,查询存储和计划强制是处理不良参数嗅探的好方法,而无需修改代码。只是说。