Sql server 执行计划中估计的行数极高

Sql server 执行计划中估计的行数极高,sql-server,sql-server-2008-r2,sql-server-2012,Sql Server,Sql Server 2008 R2,Sql Server 2012,我有一个存储过程在生产环境中的运行速度比在暂存环境中慢10倍。我看了一下执行计划,首先注意到表插入(插入到表变量@temp中)的成本在生产中为100%,在暂存中为2% 生产中的估计行数显示近2亿行!但在舞台上只有33人左右 虽然生产数据库在SQL Server 2008 R2上运行,而暂存是SQL Server 2012,但我认为这种差异不会导致这样的问题 造成如此巨大差异的原因是什么 已更新 增加了执行计划。如您所见,大量估计行显示在嵌套循环(内部联接)中,但它所做的只是对另一个表进行聚集索引

我有一个存储过程在生产环境中的运行速度比在暂存环境中慢10倍。我看了一下执行计划,首先注意到表插入(插入到表变量@temp中)的成本在生产中为100%,在暂存中为2%

生产中的估计行数显示近2亿行!但在舞台上只有33人左右

虽然生产数据库在SQL Server 2008 R2上运行,而暂存是SQL Server 2012,但我认为这种差异不会导致这样的问题

造成如此巨大差异的原因是什么

已更新

增加了执行计划。如您所见,大量估计行显示在嵌套循环(内部联接)中,但它所做的只是对另一个表进行聚集索引搜索

更新2

包含计划XML的链接

和SQL Sentry Plan Explorer视图(显示估计计数)


运行
EXEC sp\u updatestats。这将更新所有表的统计信息。如果您的统计数据出错,它可能会产生更合理的执行计划。

请不要运行EXEC sp\u updatestats;在大型系统上,可能需要数小时或数天才能完成。您可能想做的是查看正在生产中使用的查询计划。试着看看它是否有一个可以使用但没有被使用的索引。尝试重建索引(作为一种副作用,它会重建索引上的统计信息。)重建后,查看查询计划并注意它是否正在使用索引。也许您需要向表中添加索引。该表是否有聚集索引

作为一般规则,自2005年以来,SQL server自己相当好地管理统计数据。唯一需要显式更新统计信息的时间是,如果您知道SQL Server使用索引,则查询的执行速度会快得多,但事实并非如此。您可能希望(每夜或每周)运行脚本,自动测试每个表和每个索引,以查看是否需要对索引进行重新排序或重建(取决于它的分段程度)。这些脚本(在大型活动OLTP系统)R可能需要很长时间才能运行,并且当您有一个窗口来运行时,您应该仔细考虑。这个脚本有很多版本,但我经常使用这个版本:

这对我来说像个bug

估计有
90991.1
行进入嵌套循环

正在查找的表的表基数为
24826

90991.1*24826*10%=225894504.86
这与您估计的
225894000行非常接近

但执行计划显示,每次搜索仅估计
1
行。不是上面的
24826

所以这些数字加起来是不正确的。我假设它从最初的10%ball park估计值开始,然后将其调整为1,因为存在唯一约束,而没有对其他分支进行补偿调整

我看到seek正在调用标量UDF
[dbo].[TryConvertGuid]
我能够在SQL Server 2005上重现类似的行为,其中在谓词为UDF的嵌套循环内部搜索唯一索引会产生一个结果,其中从联接中估计的行数远远大于通过乘以估计的搜索行数*估计的执行数所预期的行数

但是,在您的情况下,计划中有问题部分左侧的操作符非常简单,并且对行数不敏感(rowcount top操作符或insert操作符都不会更改),因此我认为这一怪癖不会导致您注意到的性能问题


关于另一个答案的注释中的观点,即切换到临时表有助于插入的性能,这可能是因为它允许计划的读取部分并行运行(插入到表变量将阻止此操作)

抱歉,这可能太晚了,无法帮到您

SQL Server无法预测表变量。他们总是估计一排,然后正好一排回来


要获得准确的估计,以便创建更好的计划,您需要将表变量切换为临时表或cte。

查询优化器从2008年到2012年没有变化。暂存和生产中的数据是否相同?您是否尝试过更新统计信息或使用“重新编译”选项运行SP?两者之间的数据几乎相同。登台的次数少了一点,但一点也不多。谢谢。我会支持@MartinSmith的评论,并补充说它们应该是实际的计划(不是估计的)。如果您担心的话,您还可以使用SQL Sentry计划资源管理器来匿名化表名。登台执行计划也很好。顺便说一句,2012年增加了处理表格变量和解释计划的增强功能。您的DBA或DBA可能没有打开这些重新编译/重新采样选项。您不应该在2012年在dev/qa/stg中运行您计划放入2008 prod数据库的东西。特别是登台环境应该与prod完全相同,相同的db后端,相同的operation system.TT。谢谢你的提示。我已经运行过了,结果是一样的。@notlkk好的,显然还有别的事情发生。如果看不到实际的存储过程和对引用表中行数的估计,就很难对您的问题给出可靠的答案。我能说的是,如果表中有很多行,那么使用表变量可能是次优的。表变量没有统计信息,在查询中使用它们可能会产生虚假的执行计划。请改用(本地)临时表.TT。从表变量切换到临时表确实有帮助(大约快4倍,但仍然比临时表慢6倍)