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

时间:2015-07-08 21:11:35

标签: sql-server sql-server-2008-r2 sql-server-2012

enter image description here

我的存储过程在生产中比在分段中运行慢10倍。我看了一下执行计划,我注意到的第一件事就是Table Insert(进入表变量@temp)的成本在生产中是100%,在分期中是2%。

估计生产的行数显示了近2亿行!但在分期只有大约33岁。

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

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

已更新

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

UPDATED2

包含计划XML的链接 plan.xml

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

enter image description here

4 个答案:

答案 0 :(得分:1)

对我来说这看起来像个错误。

嵌套循环中有估计90,991.1行。

正在寻找的表格的基数为24,826

If there are no statistics for a column and the equality operator is used, that means the SQL can’t know the density of the column, so it uses a 10 percent fixed value.

90,991.1 * 24,826 * 10% = 225,894,504.86非常接近估算的225,894,000

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

所以这些数字并没有加起来。我会假设它从最初的10%球场估计开始,然后由于存在唯一约束而没有对其他分支进行补偿调整,因此将其调整为1。

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

但是,在您的情况下,计划中有问题部分左侧的运算符非常简单且对行数不敏感(rowcount top运算符或insert运算符都不会更改)所以我不会#39 ;我认为这个怪癖对你注意到的性能问题负责。

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

答案 1 :(得分:0)

在生产数据库上运行EXEC sp_updatestats;。这会更新所有表的统计信息。如果您的统计数据搞砸了,它可能会产生更合理的执行计划。

答案 2 :(得分:0)

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

作为一般规则,自2005年以来,SQL Server自行管理统计数据。您需要显式更新统计信息的唯一时间是,如果您知道如果SQL Server使用索引,则查询将执行的执行速度会快得多,但事实并非如此。您可能希望(每晚或每周)运行脚本,自动测试每个表和每个索引,以查看索引是否需要重新排序或重建(取决于它的碎片程度)。这些脚本(在大型活动OLTP系统上)r可能需要很长时间才能运行,当您有一个窗口运行它时,您应该仔细考虑。这个脚本有很多版本可供使用,但我经常使用这个版本: https://msdn.microsoft.com/en-us/library/ms189858.aspx

答案 3 :(得分:0)

对不起,这可能为时已晚,无法帮助您。

SQL Server无法预测表变量。他们总是估计一行,恰好一行回来。

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