我的存储过程在生产中比在分段中运行慢10倍。我看了一下执行计划,我注意到的第一件事就是Table Insert(进入表变量@temp)的成本在生产中是100%,在分期中是2%。
估计生产的行数显示了近2亿行!但在分期只有大约33岁。
虽然生产数据库在SQL Server 2008 R2上运行,而暂存是SQL Server 2012,但我认为这种差异不会导致这样的问题。
造成如此巨大差异的原因是什么?
已更新
添加了执行计划。如您所见,大量估计行显示在嵌套循环(内部联接)中,但它所做的只是聚集索引搜索到另一个表。
UPDATED2
包含计划XML的链接 plan.xml
和SQL Sentry Plan Explorer视图(显示估计的计数)
答案 0 :(得分:1)
对我来说这看起来像个错误。
嵌套循环中有估计90,991.1
行。
正在寻找的表格的基数为24,826
。
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。