5

今天,我又遇到了一个重大问题,似乎是 SQL Server 2005 中的参数嗅探。

我有一个查询将一些结果与已知的良好结果进行比较。我在结果和已知的好结果中添加了一个列,这样每个月,我都可以在两边加载一个新的月份结果,并且只比较当前月份。新列在聚集索引中排在第一位,因此新的月份将添加到末尾。

我在我的子句中添加了一个条件WHERE- 这是代码生成的,所以它是一个字面常量:

WHERE DATA_DT_ID = 20081231-- 这是多余的,因为所有 DATA_DT_ID 现在都是 20081231。

性能进入底池。从 7 秒比较大约 150 万行到 2 小时,但什么也没完成。在 SSMS 中运行生成的 SQL - 没有 SP。

我使用 SQL Server 已有 12 年了,自 10 月以来,我从未在此生产服务器上遇到过如此多的参数嗅探问题(构建版本 9.00.3068.00)。在每种情况下,这都不是因为它第一次运行时使用了不同的参数或表发生了变化。这是一个新表,它仅使用此参数运行或根本没有WHERE子句。

而且,不,我没有 DBA 访问权限,而且他们没有给我足够的权限来查看执行计划。

以至于我不确定我是否能够将这个系统交给只有几年经验的 SQL Server 用户处理。

UPDATE事实证明,尽管统计数据声称是最新的,但运行 UPDATE STATISTICS WITH FULLSCAN 可以解决问题。

最终更新即使使用 WITH RECOMPILE 和 UPDATE STATISTICS 重新创建 SP,结果还是必须以不同的方式重写查询,以使用 NOT IN 而不是 LEFT JOIN 和 NULL 检查。

4

4 回答 4

6

不是很完整的答案,但我会分享我的经验。

参数嗅探花了几年的 SQL Server 来咬我,当我离开主要从事生产 DBA 工作后回到开发人员 DBA 时。我更了解引擎、SQL 的工作原理、什么最好留给客户端等等,我是一个更好的 SQL 编码器。

例如,动态 SQL 或 CURSOR 或只是简单的坏 SQL 代码可能永远不会遭受参数嗅探。但是更好的集合编程或如何避免动态 SQL 或更优雅的 SQL 更有可能会。

我注意到它用于复杂的搜索代码(大量条件)和参数默认影响计划的复杂报告。当我看到经验不足的开发人员如何编写此代码时,它就不会遭受参数嗅探。

无论如何,我更喜欢参数屏蔽而不是 WITH RECOMPILE。无论如何更新统计信息或索引都会强制重新编译。但是为什么总是重新编译呢?我已经在其他地方回答了您的一个问题,其中提到了在编译期间嗅探参数的链接,所以我也不相信它。

参数屏蔽是一种开销,是的,但它允许优化器逐个评估查询,而不是全面重新编译。尤其是 SQL Server 2005 的语句级重新编译

SQL Server 2008 中的 OPTIMIZE FOR UNKNOWN 似乎也与屏蔽完全相同。我和我的 SQL Server MVP 同事花了一些时间调查并得出了这个结论。

于 2009-12-05T10:04:52.623 回答
4

我怀疑您的问题是由数据统计不足引起的。由于您没有对服务器的 DBA 访问权限,我建议您询问 DBA 上次更新统计信息的时间。这会对性能产生巨大影响。听起来您的表也没有很好地索引。

基本上,这“感觉”不像是参数嗅探问题,而更像是一个“健康”的数据库问题。

本文介绍如何确定上次更新统计信息的时间: 统计信息更新时间

于 2009-01-21T23:59:11.367 回答
2

我支持关于检查统计信息的评论 - 我已经看到了几个查询性能下降的情况,特别是因为统计信息已经过时。

具体来说,如果您的 PK 中有一个日期,并且 SQL Server 认为在特定日期之后只有 10 或 100 条记录,而实际上有数千条记录,它可能会选择非常低效的查询计划,因为它认为数据集要小得多比实际情况。

高温下,

  • 安德鲁
于 2009-01-22T15:12:33.143 回答
1

我有一个完全像这样的生产问题。应用程序中调用存储过程的选项卡不会显示。我对特定的过程进行了跟踪并看到了调用。应用程序在 30 秒内超时,并且 proc 将需要接近 40 - 50 秒才能完成(完全按照从跟踪中调用的方式运行 proc)。

下一步是找出导致我在执行过程中注意到的扫描的语句。所以我编写了 proc 脚本,删除了过程语法和声明的变量并在查询分析器中运行。它在 3 秒内运行!!!

我写这篇文章是为了让任何在那里寻找答案的人都知道这可能发生在 SQL 中。它源于参数嗅探问题。我找不到这个线程,因为我指出原因是缓存查询计划错误!我读过帖子,他们说它发生在一个特定的用户/价值上。但它可以发生在任何值上,一旦开始,它就可以是一个连续的事情。

我的解决方案是编写 proc 并再次运行它。是的。就这么简单。改变工作正常。无需删除和重新创建。这会导致 SQL 刷新缓存的计划,一切都很好。我还没有弄清楚如何在服务器级别禁用它。清理所有的procs太麻烦了。希望这可以帮助

于 2009-03-09T19:14:09.547 回答