外部选择中的动作的急剧CTE查询速度降低

时间:2015-01-21 18:51:29

标签: sql performance common-table-expression

我有一个复杂的报告(类似于下面的例子)它在42秒内只返回52个项目(缓慢但复杂的连接)当我执行以下操作时它会大幅减慢:

  1. 在外部选择中添加一列以获取项目的序列化列表 结果中的每个项目(添加150秒) - 参见功能。
  2. 将结果插入变量表(添加120秒),我希望扁平化会减少(1)问题,但不会减少雪茄。
  3. 我如何理解执行是先执行where然后执行select(只应对52个结果项执行)。但是,如果我使用(1)场景运行精确的52个项目,则在外部CTE选择上使用它时,仅需要7秒与添加的150个项目。

    为什么会这样,如何在没有膨胀的执行时间的情况下添加列?

    CREATE FUNCTION PriorShippers
    (
        @customerId nchar(5)
    )
    RETURNS varchar(500)
    AS
    BEGIN
        DECLARE @return varchar(500);
    
        with data as
        (
            select distinct S.CompanyName from Customers C
              join Orders O on C.CustomerID = O.CustomerID
              join Shippers S on O.ShipVia = S.ShipperID
              where C.CustomerID = @customerId
    
        ) select @return = STUFF((select CompanyName + ' ' from data FOR XML PATH('')),1,0,'')
    
        return @return
    END
    

    查询(我使用Northwind数据库 - {2012}的Install Instructions here

    DECLARE @categories TABLE
    (
        Name varchar(100),
        SourceCountry varchar(100)
    );
    insert into @categories VALUES ('Seafood', 'US');
    insert into @categories VALUES ('Beverages', 'US');
    insert into @categories VALUES ('Condiments', 'US');
    insert into @categories VALUES ('Dairy Products', 'India');
    insert into @categories VALUES ('Grains/Cereals', 'India');
    
    with data as
    (
        select C.CustomerID, C.CompanyName,
            (CASE WHEN EXISTS(select * from Orders O where O.CustomerID = C.CustomerID) THEN
                (select count(distinct CAT.CategoryID) from Orders O 
                    join [Order Details] OD on O.OrderID = OD.OrderID
                    join Products P on OD.ProductID = P.ProductID
                    join Categories CAT on P.CategoryID = CAT.CategoryID
                 where EXISTS(select * from @categories where Name = CAT.CategoryName AND SourceCountry = 'US'))
            ELSE 0 END) as 'US Orders', 
    
            (CASE WHEN EXISTS(select * from Orders O where O.CustomerID = C.CustomerID) THEN
                (select count(distinct CAT.CategoryID) from Orders O 
                    join [Order Details] OD on O.OrderID = OD.OrderID
                    join Products P on OD.ProductID = P.ProductID
                    join Categories CAT on P.CategoryID = CAT.CategoryID
                 where EXISTS(select * from @categories where Name = CAT.CategoryName AND SourceCountry = 'India'))
            ELSE 0 END) as 'India Orders'
    
        from Customers C
    
    ) select top 10 CompanyName, [US Orders], [India Orders]
        -- Below: Adding this have significant slow down
        , dbo.PriorShippers(CustomerID) 
        from data where [US Orders] > 0 Order By [US Orders]
    

1 个答案:

答案 0 :(得分:0)

您正在为每个选定的行执行用户定义的函数。简而言之,不要这样做。

直接在报告中将函数中的代码移动到DTE中。

另外,我注意到你的计数的连接是相同的。它们看起来像是第三个DTE的主要候选者,您可以简单地加入其中以进一步提高整体查询的性能。