如何加速这个查询?

时间:2017-06-14 09:49:10

标签: sql sql-server tsql

您对如何加快此查询有所了解:

SELECT  Vosol = ( CASE WHEN EXISTS ( SELECT Id
                                     FROM   trs.CollectionHeaderView AS chv
                                     WHERE  chv.ItemNum = itm.ItemNum
                                            AND chv.CollectionType = '1' )
                       THEN ISNULL(itm.Amount, 0)
                       ELSE 0
                  END ) ,
        Vakhast = ( CASE WHEN EXISTS ( SELECT   Id
                                       FROM     trs.CollectionHeaderView AS chv
                                       WHERE    chv.ItemNum = itm.ItemNum
                                                AND chv.CollectionType = '2' )
                         THEN ISNULL(itm.Amount, 0)
                         ELSE 0
                    END )
FROM    trs.TrsDocRcvItem AS itm
        LEFT JOIN trs.TrsDocRcvHeader AS hdr ON itm.HeaderRef = hdr.Id
        LEFT JOIN acc.DL AS dl ON dl.Id = hdr.DLRef
        LEFT JOIN trs.TrsDocType AS docType ON docType.Id = hdr.DocTypeRef
        INNER JOIN sle.SleCustomer AS customer ON customer.DLRef = dl.Id
        LEFT JOIN trs.AccOperation AS operation ON operation.Id = itm.AccOperationRef
WHERE   hdr.DocTypeRef NOT IN ( 1141, 1142, 1241, 1242 )
        AND ( hdr.State = '1'
              OR hdr.State = '2'
            )
        AND operation.StateType = '1'

我正在尝试优化sql查询,现在需要大约6秒才能执行。 我还能做些什么来加速这个查询? 我正在使用Microsoft Sql Server。

2 个答案:

答案 0 :(得分:2)

使用OUTER APPLY删除两个相关的子查询。

SELECT Vosol = CASE WHEN chv1 IS NOT NULL THEN Isnull(itm.Amount, 0) ELSE 0 END,
       Vakhast = CASE WHEN chv2 IS NOT NULL THEN Isnull(itm.Amount, 0) ELSE 0 END
FROM   trs.TrsDocRcvItem AS itm
       INNER JOIN trs.TrsDocRcvHeader AS hdr
              ON itm.HeaderRef = hdr.Id
       --LEFT JOIN acc.DL AS dl
       --       ON dl.Id = hdr.DLRef
       --LEFT JOIN trs.TrsDocType AS docType
             -- ON docType.Id = hdr.DocTypeRef
       --INNER JOIN sle.SleCustomer AS customer
       --        ON customer.DLRef = dl.Id
       INNER JOIN trs.AccOperation AS operation
              ON operation.Id = itm.AccOperationRef
       OUTER apply (SELECT Max(CASE WHEN chv.CollectionType = '1' THEN id END) AS chv1,
                           Max(CASE WHEN chv.CollectionType = '2' THEN id END) AS chv2
                    FROM   trs.CollectionHeaderView AS chv
                    WHERE  chv.ItemNum = itm.ItemNum
                           AND chv.CollectionType IN ( '1', '2' )) oa
WHERE  hdr.DocTypeRef NOT IN ( 1141, 1142, 1241, 1242 )
       AND hdr.State IN ( '1', '2' )
       AND operation.StateType = '1' 

我已对acc.DLsle.SleCustomer表进行了注释。除了过滤记录之外,我没有看到它的任何用途。如果你真的需要它,那么取消注释它。

此外,我评论了trs.TrsDocType表再次没用。除非它与trs.TrsDocRcvHeader表有一对多的关系。如果它具有一对多的关系,那么结果就会无缘无故地重复,因为您没有从trs.TrsDocType表中选择任何内容。

如果查询运行缓慢,则需要在所涉及的表上创建Indexes。另外,请确保statistics是最新的

在分析执行计划后,TrsDocRcvItem表费用47%。在TrsDocRcvItem表上创建索引应该有助于查询

CREATE NONCLUSTERED INDEX NIX_TrsDocRcvItem
ON [Trs].[TrsDocRcvItem] (AccOperationRef,ItemNum,HeaderRef)
INCLUDE (Amount)

您已发布的执行计划的建议索引

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [Trs].[TrsDocRcvItem] ([AccOperationRef])
INCLUDE ([ItemNum],[Amount],[HeaderRef])

答案 1 :(得分:1)

SELECT  Vosol = ( CASE WHEN EXISTS ( SELECT Id
                                     FROM   trs.CollectionHeaderView AS chv
                                     WHERE  chv.ItemNum = itm.ItemNum
                                            AND chv.CollectionType = '1' )
                       THEN ISNULL(itm.Amount, 0)
                       ELSE 0
                  END ) ,
        Vakhast = ( CASE WHEN EXISTS ( SELECT   Id
                                       FROM     trs.CollectionHeaderView AS chv
                                       WHERE    chv.ItemNum = itm.ItemNum
                                                AND chv.CollectionType = '2' )
                         THEN ISNULL(itm.Amount, 0)
                         ELSE 0
                    END )
FROM    trs.TrsDocRcvItem AS itm
        INNER JOIN 
        (
    SELECT * FROM trs.TrsDocRcvHeader
    WHERE   DocTypeRef NOT IN ( 1141, 1142, 1241, 1242 )
                AND ( State = '1' OR State = '2' )

        ) hdr ON itm.HeaderRef = hdr.Id
        LEFT JOIN acc.DL AS dl ON dl.Id = hdr.DLRef
        LEFT JOIN trs.TrsDocType AS docType ON docType.Id = hdr.DocTypeRef
        INNER JOIN sle.SleCustomer AS customer ON customer.DLRef = dl.Id
        INNER JOIN 
        ( SELECT * FROM trs.AccOperation WHERE StateType = '1'
        ) operation operation.Id = itm.AccOperationRef

您可以替换

WHERE   hdr.DocTypeRef NOT IN ( 1141, 1142, 1241, 1242 )
        AND ( hdr.State = '1'
              OR hdr.State = '2'
            )
        AND operation.StateType = '1'

INNER JOIN 
        (
    SELECT * FROM trs.TrsDocRcvHeader
    WHERE   DocTypeRef NOT IN ( 1141, 1142, 1241, 1242 )
                AND ( State = '1' OR State = '2' )

        ) hdr ON itm.HeaderRef = hdr.Id

INNER JOIN 
        ( SELECT * FROM trs.AccOperation WHERE StateType = '1'
        ) operation operation.Id = itm.AccOperationRef

我希望它会对你有所帮助。