【发布时间】: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