【问题标题】:SQL Server query plan cache and plan reuse for stored proceduresSQL Server 查询计划缓存和存储过程的计划重用
【发布时间】:2014-01-22 23:15:12
【问题描述】:

我在 SQL Server 2012 数据库中有一个大约 300 万行的表。 ETL 包向表中插入了大约 50,000 个新行。

在插入之后,ETL 包使用存储过程更新新添加的行。该过程有一个ExecutionID 的输入参数,用于仅过滤插入的行。我已经根据查询创建了索引,如果表的统计信息是最新的,那么查询性能就很好。但是,统计信息不会每天更新,因为添加的记录数不会强制触发自动更新统计信息。

我对存储过程计划的理解是优化器缓存计划,然后重复使用它,直到计划失效。因此,我期望如果我按照我想要的计划运行该程序一次,该计划应该被重用。但是,我在同一过程的计划缓存中看到了多个计划。

为什么会这样?换句话说,为什么 SQL Server 会为同一个查询缓存不同的计划?

在这种情况下,我应该在调用程序之前手动更新统计信息吗?似乎优化器使用参数值来确定计划,并且由于没有为新一批数据更新统计信息,因此它不会使用正确的计划。

【问题讨论】:

  • 你的程序代码是什么样的?如果你为每个ExecutionID 建立一个单独的查询,那么就没有什么可以缓存和重用了。另外:计划将保留在缓存中直到 SQL Server 选择丢弃它,因此如果您的系统内存紧张,它可能会很快被丢弃....
  • 不确定建立单独的查询是什么意思。 proc为所有历史数据构建一个CTE,只过滤与通过参数传递的最新ExecutionID相关的数据,然后根据ExecutionID、CTE等条件再次更新表。我在监控后注意到的是,一旦缓存了“坏”计划,它就会重复使用它,直到更新统计信息。因此,如果我现在查询缓存的计划,我会看到同一个 proc 的 2 个计划。没有使用的好和重复使用的“坏”。如果我更新统计数据并重新运行 proc,则使用好的。
  • 但是,由于第二天我们有一个新的 ExecutionID,因此再次使用了错误的计划,可能是因为优化器检查了统计数据并确定该计划(好的)不是使用的最佳计划,并且基于手头的信息它使用另一个。这是否意味着缓存计划的参数嗅探和重用依赖于统计信息等其他内容?

标签: sql sql-server


【解决方案1】:

如果您的ExecutionID 是自动递增的,那么最有可能发生的是各种直方图和统计数据中没有新值(因为它是新值)。结果,优化器对该数字的基数一无所知,并且做出了错误的猜测。

我建议你想要

  1. 导入数据
  2. 重建统计数据
  3. 进行更新

或者你可以冻结一个计划

http://blogs.msdn.com/b/sqlblog/archive/2009/02/19/plan-guides-plan-freezing-in-sql-server-2005-2008.aspx

或者,您可以在更新上放置一个索引提示,以便它无论如何都使用正确的计划。

【讨论】:

  • 感谢您的回答。您建议的方法将起作用。如前所述,我试图了解为什么不使用缓存计划,并且优化器生成了一个新计划,从而导致了问题。基于 cmets,我认为缓存计划并不总是根据统计数据等内容使用。换句话说,参数嗅探和重用缓存计划取决于其他标准。
猜你喜欢
  • 2020-10-16
  • 1970-01-01
  • 2011-03-22
  • 2011-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多