sql-server – 使用完全不同的计划的T-SQL查询,具体取决于我正在更新的行数

前端之家收集整理的这篇文章主要介绍了sql-server – 使用完全不同的计划的T-SQL查询,具体取决于我正在更新的行数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个带有“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

Here’s the quick plan

And here’s the slower one

在我设置查询的方式或提供的执行计划中是否有任何明显的东西会使查询引擎做出错误的选择?如有必要,我还可以包括所涉及的表定义以及在其上定义的索引.

对于那些要求仅限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

解决方法

dimTime的索引正在改变.更快的计划是使用_dta索引.首先,确保在sys.indexes中没有标记为假设索引.

认为你可以通过使用#mac表来过滤一些参数化,而不是像@StartDate和@enddate之间那样只提供这个WHERE t.TimeValue的开始/结束日期.摆脱那个临时表.

猜你在找的MsSQL相关文章