我有一个带有“ TOP(X)”子句的SQL UPDATE语句,而我要更新值的行大约有40亿行。当我使用“ TOP(10)”时,我得到一个几乎立即执行的执行计划,但是当我使用“ TOP(50)”或更大时,查询永远不会完成(至少在我等待时)。它使用完全不同的执行计划。较小的查询使用一个非常简单的计划,该计划带有一对索引查找和一个嵌套循环联接,其中完全相同的查询(UPDATE语句的TOP子句中的行数不同)使用的方案涉及两个不同的索引查找,表假脱机,并行性以及其他一系列复杂性。
我已经使用“ OPTION(USE PLAN ...)”来强制它使用由较小查询生成的执行计划-当我这样做时,我可以在几秒钟内更新多达100,000行。我知道查询计划是好的,但是SQL Server仅在只涉及少量行的情况下才会自行选择该计划-更新中任何相当大的行数都会导致次优计划。
我以为应该归咎于并行性,所以我MAXDOP 1
对查询进行设置,但是没有任何效果-这一步骤已经过去,但是糟糕的选择/性能却没有。我也sp_updatestats
今天早上跑了,以确保不是这个原因。
我已经附上了两个执行计划-计划越短也越快。此外,这是有问题的查询(值得注意的是,无论行数是大还是小,我包含的SELECT似乎都是快速的):
update top (10000) FactSubscriberUsage3
set AccountID = sma.CustomerID
--select top 50 f.AccountID, sma.CustomerID
from FactSubscriberUsage3 f
join dimTime t
on f.TimeID = t.TimeID
join #mac sma
on f.macid = sma.macid
and t.TimeValue between sma.StartDate and sma.enddate
where f.AccountID = 0 --There's a filtered index on the table for this
我设置查询的方式或执行计划中是否有任何明显的内容,这会导致查询引擎做出错误的选择?如有必要,我还可以包括所涉及的表定义以及在其上定义的索引。
对于那些要求仅提供统计信息的数据库对象版本的人: 我什至没有意识到您可以做到这一点,但这完全有道理!我试图为仅统计数据的数据库生成脚本,以便其他人可以自己测试执行计划,但是我可以在过滤后的索引上生成统计数据/直方图(似乎脚本中的语法错误),所以我那里运气不好。我尝试删除过滤器,但查询计划很接近,但并不完全相同,我也不想派人追赶。
更新和一些更完整的执行计划: 首先,SQL Sentry的Plan Explorer是一个了不起的工具。在查看本网站上的其他查询计划问题之前,我什至不知道它的存在,而且关于我的查询如何执行还有很多话要说。尽管我不确定如何解决该问题,但他们明确指出了问题所在。
这是10、100和1000行的摘要-您可以看到1000行查询与其他查询完全不同:
您可以看到第三个查询的读取次数非常可笑,因此显然它在做完全不同的事情。这是带有行数的估计执行计划。 1000行估计执行计划:
这是执行计划的实际结果(顺便说一句,“永不完成”,事实证明我的意思是“在一小时内完成”)。 1000行实际执行计划
我注意到的第一件事是,而不是从dimTime表拉60K行一样,它预计,它的实际拉动1.6十亿,用B。查看我的查询,我不确定它是如何从dimTime表中撤回这么多行的。我使用的BETWEEN运算符只是确保我根据事实表中的时间记录从#mac中提取正确的记录。但是,当我在WHERE子句中添加一行以将t.TimeValue(或t.TimeID)过滤为单个值时,我可以在几秒钟内成功更新100,000行。结果,如我所包含的执行计划中所述,很明显这是我的时间表是问题所在,但是我不确定如何更改联接条件来解决此问题并保持准确性。有什么想法吗?
供参考,此处为100行更新的计划(带行计数)。您可以看到它命中相同的索引,并且仍然有大量的行,但是问题的严重程度相差无几。 具有行数的100行执行:
from #mac sma join f on f.macid = sma.macid join dimTime t on f.TimeID = t.TimeID and t.TimeValue between sma.StartDate and sma.enddate
与from #mac join t on t.TimeValue between sma.StartDate and sma.enddate join f on f.TimeID = t.TimeID and f.macid = sma.macid
TOP 50
仍应快速执行。您可以上传XML计划吗?我需要查看行数。您可以TOP 50
使用maxdop 1并作为选择而不是作为更新来运行计划吗?(试图简化/平分搜索空间)。
t.TimeValue between sma.StartDate and sma.enddate
可能最终会生成更多无用的行,这些行随后会在针对FactSubscriber的联接中被过滤掉,因此不要最终得到最终结果。
sp_updatestatistics
在桌子上跑了吗?