执行计划中的估计行数极高
Extrememly High Estimated Number of Rows in Execution Plan
我有一个存储过程 运行 在生产中比在暂存中慢 10 倍。我查看了执行计划,我注意到的第一件事是 Table 插入(插入 table 变量 @temp)的成本在生产中为 100%,在暂存中为 2%。
生产中的估计行数显示将近 2 亿行!但是分期只有33左右。
虽然生产数据库在 SQL Server 2008 R2 上 运行 而暂存是 SQL Server 2012,但我认为这种差异不会导致这样的问题。
造成如此巨大差异的原因是什么?
已更新
添加了执行计划。如您所见,大量估计行显示在嵌套循环(内部联接)中,但它所做的只是聚集索引查找另一个 table。
UPDATED2
Link 包含计划 XML
plan.xml
和 SQL Sentry Plan Explorer 视图(显示估计数量)
运行 EXEC sp_updatestats;
在生产数据库上。这会更新所有表的统计信息。如果您的统计数据搞砸了,它可能会产生更合理的执行计划。
请不要运行执行sp_updatestats;在大型系统上,可能需要数小时或数天才能完成。您可能想要做的是查看生产中使用的查询计划。尝试查看它是否具有可以使用和未被使用的索引。尝试重建索引(作为副作用,它会重建索引的统计信息。)重建后查看查询计划并注意它是否正在使用索引。也许你们很多人需要为 table 添加一个索引。 table 是否有聚簇索引?
作为一般规则,自 2005 年以来,SQL 服务器自行管理统计信息的效果相当好。唯一需要显式更新统计信息的情况是,如果您知道如果 SQL 服务器使用索引,查询将执行得更快,但事实并非如此。您可能希望 运行(每晚或每周)自动测试每个 table 和每个索引的脚本,以查看索引是否需要重组或重建(取决于它的碎片化程度)。这些类型的脚本(在大型活动的 OLTP 系统上)可能需要很长时间才能 运行 并且当你有 window 到 运行 时你应该仔细考虑。这个脚本有很多版本,但我经常使用这个:
https://msdn.microsoft.com/en-us/library/ms189858.aspx
我觉得这像是一个错误。
估计有 90,991.1
行进入嵌套循环。
正在查找的 table 的 table 基数是 24,826
。
90,991.1 * 24,826 * 10% = 225,894,504.86
这与您估计的 225,894,000
行非常接近
但执行计划显示每次查找仅估计 1
行。不是上面的 24,826
。
所以这些数字不相加。我假设它从最初的 10% 球场估计开始,然后由于存在唯一约束而将其调整为 1,而不对其他分支进行补偿调整。
我看到搜索正在调用标量 UDF [dbo].[TryConvertGuid]
我能够在 SQL Server 2005 上重现类似的行为,其中在嵌套循环内部的唯一索引上使用作为 UDF 的谓词产生的结果是,从连接中估计出的行数比通过乘以估计的查找行数 * 估计的执行数所预期的要大得多。
但是,在您的情况下,计划中有问题的部分左侧的运算符非常简单并且对行数不敏感(rowcount top 运算符或插入运算符都不会改变)所以我不'认为这个怪癖是造成您注意到的性能问题的原因。
关于另一个答案的评论中指出切换到临时 table 有助于提高插入性能,这可能是因为它允许计划的读取部分并行运行(插入到table 变量会阻止这个)
抱歉,这可能来不及帮助你了。
Table SQL 服务器无法预测变量。他们总是估计一排,正好一排回来。
要获得准确的估计以便制定更好的计划,您需要将 table 变量切换为临时 table 或 cte。
我有一个存储过程 运行 在生产中比在暂存中慢 10 倍。我查看了执行计划,我注意到的第一件事是 Table 插入(插入 table 变量 @temp)的成本在生产中为 100%,在暂存中为 2%。
生产中的估计行数显示将近 2 亿行!但是分期只有33左右。
虽然生产数据库在 SQL Server 2008 R2 上 运行 而暂存是 SQL Server 2012,但我认为这种差异不会导致这样的问题。
造成如此巨大差异的原因是什么?
已更新
添加了执行计划。如您所见,大量估计行显示在嵌套循环(内部联接)中,但它所做的只是聚集索引查找另一个 table。
UPDATED2
Link 包含计划 XML plan.xml
和 SQL Sentry Plan Explorer 视图(显示估计数量)
运行 EXEC sp_updatestats;
在生产数据库上。这会更新所有表的统计信息。如果您的统计数据搞砸了,它可能会产生更合理的执行计划。
请不要运行执行sp_updatestats;在大型系统上,可能需要数小时或数天才能完成。您可能想要做的是查看生产中使用的查询计划。尝试查看它是否具有可以使用和未被使用的索引。尝试重建索引(作为副作用,它会重建索引的统计信息。)重建后查看查询计划并注意它是否正在使用索引。也许你们很多人需要为 table 添加一个索引。 table 是否有聚簇索引?
作为一般规则,自 2005 年以来,SQL 服务器自行管理统计信息的效果相当好。唯一需要显式更新统计信息的情况是,如果您知道如果 SQL 服务器使用索引,查询将执行得更快,但事实并非如此。您可能希望 运行(每晚或每周)自动测试每个 table 和每个索引的脚本,以查看索引是否需要重组或重建(取决于它的碎片化程度)。这些类型的脚本(在大型活动的 OLTP 系统上)可能需要很长时间才能 运行 并且当你有 window 到 运行 时你应该仔细考虑。这个脚本有很多版本,但我经常使用这个: https://msdn.microsoft.com/en-us/library/ms189858.aspx
我觉得这像是一个错误。
估计有 90,991.1
行进入嵌套循环。
正在查找的 table 的 table 基数是 24,826
。
90,991.1 * 24,826 * 10% = 225,894,504.86
这与您估计的 225,894,000
但执行计划显示每次查找仅估计 1
行。不是上面的 24,826
。
所以这些数字不相加。我假设它从最初的 10% 球场估计开始,然后由于存在唯一约束而将其调整为 1,而不对其他分支进行补偿调整。
我看到搜索正在调用标量 UDF [dbo].[TryConvertGuid]
我能够在 SQL Server 2005 上重现类似的行为,其中在嵌套循环内部的唯一索引上使用作为 UDF 的谓词产生的结果是,从连接中估计出的行数比通过乘以估计的查找行数 * 估计的执行数所预期的要大得多。
但是,在您的情况下,计划中有问题的部分左侧的运算符非常简单并且对行数不敏感(rowcount top 运算符或插入运算符都不会改变)所以我不'认为这个怪癖是造成您注意到的性能问题的原因。
关于另一个答案的评论中指出切换到临时 table 有助于提高插入性能,这可能是因为它允许计划的读取部分并行运行(插入到table 变量会阻止这个)
抱歉,这可能来不及帮助你了。
Table SQL 服务器无法预测变量。他们总是估计一排,正好一排回来。
要获得准确的估计以便制定更好的计划,您需要将 table 变量切换为临时 table 或 cte。