我使用了“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
在我设置查询的方式或提供的执行计划中是否有任何明显的东西会使查询引擎做出错误的选择?如有必要,我还可以包括所涉及的表定义以及在其上定义的索引.
对于那些要求仅限stats版本的数据库对象的人:
我甚至没有意识到你能做到这一点,但它完全有道理!我试图为仅限stats的数据库生成脚本,以便其他人可以自己测试执行计划,但我可以在我的过滤索引上生成生成统计/直方图(脚本中的语法错误,似乎),所以我是那里运气不好.我尝试删除过滤器,查询计划很接近,但不完全相同,我不想发送任何人进行鹅追逐.
更新和一些更完整的执行计划:
首先,SQL Sentry’s Plan Explorer是一个令人难以置信的工具.在查看本网站上的其他查询计划问题之前,我甚至都不知道它存在,并且它有很多关于我的查询执行情况的说法.虽然我不确定如何解决这个问题,但他们明白问题是什么.
以下是10行,100行和1000行的摘要 – 您可以看到1000行查询的方式与其他行不一致:
你可以看到第三个查询的读取次数非常多,所以它显然做了一些完全不同的事情.这是估计的执行计划,包括行数.
1000-row estimated execution plan:
这是执行计划的实际结果(顺便说一句,“从未完成”,事实证明我的意思是“在一小时内完成”).
1000-row actual execution plan
我注意到的第一件事是,不是像它期望的那样从dimTime表中拉出60K行,而是用B来实际拉动16亿行.看看我的查询,我不确定它是如何从那里拉出那么多行的dimTime表.我正在使用的BETWEEN运算符确保我根据Fact表中的时间记录从#mac中提取正确的记录.但是,当我在WHERE子句中添加一行,我将t.TimeValue(或t.TimeID)过滤为单个值时,我可以在几秒钟内成功更新100,000行.因此,正如我所包含的执行计划中所明确的那样,显然我的时间表是问题,但我不确定如何更改连接标准以解决此问题并保持准确性.有什么想法吗?
作为参考,这里是100行更新的计划(带行计数).您可以看到它达到相同的索引,并且仍然有大量的行,但远不及相同的问题幅度.
100 row execution with row counts:
解决方法
认为你可以通过使用#mac表来过滤一些参数化,而不是像@StartDate和@enddate之间那样只提供这个WHERE t.TimeValue的开始/结束日期.摆脱那个临时表.