为什么会出现显示我的执行计划了一个排序?(Why is there a sort showing u

2019-08-06 02:32发布

我有下面的SQL查询运行速度非常慢。 我接过一看执行计划,并声称,在Files.OrderId一种是最高的运行成本(53%)。 为什么会变成这样发生的,如果我没有被任何地方的OrderId订货? 是创造File.OrderId索引我最好的选择?

执行计划 ,如果有人有兴趣。

with custOrders as
(
    SELECT c.firstName + ' ' + c.lastname as Customer, c.PartnerId , c.CustomerId,o.OrderId,o.CreateDate, c.IsPrimary
    FROM Customers c
    LEFT JOIN CustomerRelationships as cr
        ON c.CustomerId = cr.PrimaryCustomerId
    INNER JOIN Orders as o
       ON c.customerid = o.customerid 
           OR (cr.secondarycustomerid IS NOT NULL AND o.customerid = cr.secondarycustomerid)
    where c.createdate >= @FromDate + ' 00:00' 
       AND c.createdate <= @ToDate + ' 23:59' 
),
 temp as
(
SELECT Row_number() 
         OVER ( 
           ORDER BY c.createdate DESC)                    AS 'row_number', 
       c.customerid as customerId, 
       c.partnerid as partnerId, 
       c.Customer, 
       c.orderid as OrderId, 
       c.createdate as CreateDate, 
       Count(f.orderid)                                   AS FileCount, 
       dbo.Getparentcustomerid(c.isprimary, c.customerid) AS ParentCustomerId, 
       au.firstname + ' ' + au.lastname                   AS Admin, 
       '' as blank, 
       0  as zero
FROM   custOrders c 
       INNER JOIN files f 
               ON c.orderid = f.orderid 
       INNER JOIN admincustomers ac 
               ON c.customerid = ac.customerid 
       INNER JOIN adminusers au 
               ON ac.adminuserid = au.id 
       INNER JOIN filestatuses s 
               ON f.statusid = s.statusid 
WHERE  ac.adminuserid IS NOT NULL 
       AND f.statusid NOT IN ( 5, 6 ) 
GROUP  BY c.customerid, 
          c.partnerid, 
          c.Customer, 
          c.isprimary, 
          c.orderid, 
          c.createdate, 
          au.firstname, 
          au.lastname 
)

Answer 1:

SQL Server有三种算法从当它需要连接两个表来选择。 在嵌套循环连接中,哈希联接和排序合并联接。 哪一个选择它立足于成本估算。 在这种情况下,它想通,这基于它提供了一个排序合并,加入的信息是正确的选择。

在SQL Server执行计划排序合并是splitt成两个运营商来说,排序和融合连接,因为排序操作可能不是必要的,例如,如果数据已经排序。

如需更多信息,有关加入这里看看我的加盟系列: http://sqlity.net/en/1146/a-join-a-day-introduction/有关排序-MERG-加入的文章是在这里: HTTP:// sqlity.net/en/1480/a-join-a-day-the-sort-merge-join/


为了使您的查询速度更快,我首先会看索引。 你有一堆查询聚簇索引扫描的。 如果你可以替换其中的几个与你寻求将是最有可能更好。 还要检查是否是SQL Server的产生估计在实际的执行计划符合实际的行数。 如果他们是相差不远,SQL服务器常常使错误的选择。 因此,提供更好的统计数据可以帮助您查询的性能了。



Answer 2:

SQL Server执行排序,使合并的数据集中到那种运营权,并在记录之间加入Orders表。 合并连接本身是加入数据集中的所有记录一个非常有效的方式,但它要求每个数据集要加入根据连接键,并在相同的顺序进行排序。

由于PK_Orders键已经被订购OrderID ,SQL Server将决定排序的加入(其他的东西来排序的右边)的另一端,使两个数据集可在该点被合并在一起,以利用该计划。 合并加盟常见的替代方法是散列连接,但不会帮助你,因为你会,而不是有一个昂贵的散列连接操盘的排序和合并。 查询优化器已确定的排序和合并是在这种情况下更有效。

在计划中昂贵的步骤的根本原因是所有的记录从订单表合并到数据集中的需求。 有没有办法来限制从即将到来的记录files表? 在索引files.statusid如果记录未在5,6是表的总大小小于10%可能会有所帮助。

该QO认为,大多数的记录会在年底被过滤掉。 尝试尽可能多的那些过滤条件推回记录源,这样少的记录在计划中进行处理。

编辑:我忘了提,这是非常有帮助的,我们可以看一个执行计划。 有什么办法,我们可以得到一个实际的执行计划的结果看到的记录通过这些运营商去实数? 有时,估计记录计数可能有点过。

编辑:展望深入到第二至最后一个过滤器运营商的上游领域,总结如下:

c.CustomerId=o.CustomerId
OR o.CustomerId=cr.SecondaryCustomerId AND cr.SecondaryCustomerId IS NOT NULL

看起来像SQL Server正在产生交叉之间的所有可能的匹配记录之间的联接OrdersCustomers查询(2号到最后一个过滤器操作权计划)到这点,然后看着每一条记录与该条件看如果它确实匹配。 请注意,进入过滤器的线是如何真正的脂肪和出来的线是真的瘦了? 这是因为预计行数从21K是运营商后进入4。 忘了我刚才说,这可能是该计划的主要问题。 即使有这些列的索引,由于连接条件太复杂的SQL Server不能使用它们。 它使计划中的所有记录合并,而不是寻求正是你需要,因为它不能使用完整的连接谓词马上的人在一起。

我首先想到的是修改CTE custOrders两个数据集的工会:一个使用CustomerId和一个使用SecondaryCustomerId加入。 这将复制CTE其余的工作,但如果它能够正确使用索引的,它可能是一个巨大的胜利。



Answer 3:

我认为,排序发生了这个连接:

FROM   custOrders c 
       INNER JOIN files f 
               ON c.orderid = f.orderid 

因为查询也使用statusid列我将创建包含列的OrderID文件和statusid的索引。

您可能还需要考虑以下几点变化:

  1. 你不需要“ac.adminuserid IS NOT NULL”,因为这是由内覆盖adminusers和admincustomers之间的连接
  2. 改变测试“f.statusid NOT IN(5,6)”到正条件(例如在)作为阴性条件来处理更昂贵。


Answer 4:

我知道这个问题是很老,但我有同样的问题,并意识到有一个完全不同的原因,我的表突然变慢。 症状明显,以前快如闪电一样,更新缓慢的看法。 “排序”给予40%的成本。 该解决方案可证明有用的人,这很简单。 当联接表,确保你加入了一个“喜欢像”的基础上。 我加入的ID两个表。 然而,在一个表我的ID被设置为INT与其他作为nvarchar的。 我纠正这让他们都定义为相同的类型和该视图是回闪电速度。

希望这会帮助别人,以避免每周花费试图找出什么地方错了SQL,当它真的PEBKAC时刻。

(问题键盘和椅子之间存在)



文章来源: Why is there a sort showing up in my execution plan?