使用表的连接查询需要很长时间才能执行5分钟

时间:2017-04-27 06:13:37

标签: sql sql-server

SELECT
    B.AccountBranchID
    ,B.VoucherNo
    ,B.BranchName AS BranchName
    ,B.InvoiceNo
    ,CONVERT(VARCHAR, B.InvoiceDate, 103) AS InvoiceDate
    ,CONVERT(VARCHAR, B.VoucherDate, 103) AS VoucherDate
    ,B.CustomerName
    ,B.RefID
    ,LN.AccountName AS LedgerName
    ,b.SalesPersonName AS SalesPersonName
    ,LN.LedgerCode
    ,B.AgentName
    ,B.ShipperName
    ,B.Segment
    ,B.TransactionType
    ,B.JobNo
    ,CONVERT(VARCHAR, B.JOBDate, 103) AS JOBDate
    ,B.MAWBNo
    ,B.HAWBNo
    ,B.AccountName
    ,B.LedgerCode AS AccountLedgerCode
    ,B.CurrencyCode
    ,ISNULL(B.Amount, 0) AS Amount
    ,B.ChargeExRate
    ,(CASE B.CRDR
        WHEN 'CR' THEN (B.ChargeBaseAmount * -1)
        ELSE B.ChargeBaseAmount
    END) AS ChargeBaseAmount
    ,(CASE B.CRDR
        WHEN 'CR' THEN 'Credit'
        ELSE 'Debit'
    END) AS CRDR

FROM VW_VoucherTR AS B
INNER JOIN VW_VoucherTR AS LN
    ON B.VoucherID = LN.VoucherID
WHERE B.CompanyID = @CompanyID
AND (CASE @Type
    WHEN 'I' THEN B.InvoiceDate
    ELSE B.VoucherDate
END) BETWEEN ISNULL(@FromDate, (SELECT
        FYearStart
    FROM Secmst_FinancialYear
    WHERE FyearId = @yearID)
) AND ISNULL(@ToDate, GETDATE())
AND (@Segment IS NULL
OR B.Segment = @Segment)
AND (@BranchMappingID IS NULL
OR B.BranchMappingID = @BranchMappingID)
AND B.VoucherTypeCode IN ('sv')
AND B.IsDeleted = 0
AND (B.GroupName <> 'Sundry Creditors'
AND B.GroupName <> 'Sundry Debtors')
AND LN.GroupName IN ('Sundry Debtors', 'Sundry Creditors')

2 个答案:

答案 0 :(得分:0)

BETWEEN中的子查询可能正在杀死你。你看过执行计划了吗?

BETWEEN ISNULL(@FromDate, ( SELECT FYearStart FROM Secmst_FinancialYear WHERE FyearId = @yearID )) AND ISNULL(@ToDate, GETDATE())

正在发生的事情是你在每一行都运行该查询,而且根据我的外表,这是不必要的,因为你只需要那里的静态日期(不是基于连接的行的任何东西。)

试试这个:

DECLARE @FromDateActual datetime = ISNULL(@FromDate, (
                SELECT FYearStart
                FROM Secmst_FinancialYear
                WHERE FyearId = @yearID
                ));
DECLARE @ToDateActual datetime = ISNULL(@ToDate, GETDATE());

SELECT B.AccountBranchID
    ,B.VoucherNo
    ,B.BranchName AS BranchName
    ,B.InvoiceNo
    ,convert(VARCHAR, B.InvoiceDate, 103) AS InvoiceDate
    ,convert(VARCHAR, B.VoucherDate, 103) AS VoucherDate
    ,B.CustomerName
    ,B.RefID
    ,LN.AccountName AS LedgerName
    ,b.SalesPersonName AS SalesPersonName
    ,LN.LedgerCode
    ,B.AgentName
    ,B.ShipperName
    ,B.Segment
    ,B.TransactionType
    ,B.JobNo
    ,convert(VARCHAR, B.JOBDate, 103) AS JOBDate
    ,B.MAWBNo
    ,B.HAWBNo
    ,B.AccountName
    ,B.LedgerCode AS AccountLedgerCode
    ,B.CurrencyCode
    ,ISNULL(B.Amount, 0) AS Amount
    ,B.ChargeExRate
    ,(
        CASE B.CRDR
            WHEN 'CR'
                THEN (B.ChargeBaseAmount * - 1)
            ELSE B.ChargeBaseAmount
            END
        ) AS ChargeBaseAmount
    ,(
        CASE B.CRDR
            WHEN 'CR'
                THEN 'Credit'
            ELSE 'Debit'
            END
        ) AS CRDR
FROM VW_VoucherTR AS B
INNER JOIN VW_VoucherTR AS LN ON B.VoucherID = LN.VoucherID
WHERE B.CompanyID = @CompanyID
    AND (
        CASE @Type
            WHEN 'I'
                THEN B.InvoiceDate
            ELSE B.VoucherDate
            END
        ) BETWEEN @FromDateActual
        AND @ToDateActual
    AND (
        @Segment IS NULL
        OR B.Segment = @Segment
        )
    AND (
        @BranchMappingID IS NULL
        OR B.BranchMappingID = @BranchMappingID
        )
    AND B.VoucherTypeCode IN ('sv')
    AND B.IsDeleted = 0
    AND (
        B.GroupName <> 'Sundry Creditors'
        AND B.GroupName <> 'Sundry Debtors'
        )
    AND LN.GroupName IN (
        'Sundry Debtors'
        ,'Sundry Creditors'
        )

除此之外,您可以考虑添加非聚集索引。查询分析器甚至可以建议一对。但是你需要小心,具体取决于数据的使用和加载方式,因为太多的索引或大的索引会导致其他地方出现进一步的性能问题(行插入,页面碎片等)。

答案 1 :(得分:0)

可能有很多原因,但有一点很明显。以下部分不是sargable

 (CASE @Type
    WHEN 'I' THEN B.InvoiceDate
    ELSE B.VoucherDate
END) BETWEEN ISNULL(@FromDate, (SELECT
        FYearStart
    FROM Secmst_FinancialYear
    WHERE FyearId = @yearID)
) AND ISNULL(@ToDate, GETDATE())

应该重写为sargable,以便可以使用索引。

SELECT @FromDate = ISNULL(@FromDate, (SELECT
        TOP 1 FYearStart 
        FROM Secmst_FinancialYear
        WHERE FyearId = @yearID)) )

SELECT @ToDate = ISNULL(@ToDate, GETDATE())

SELECT
...
WHERE
...
AND
((@Type='I' AND B.InvoiceDate BETWEEN @FromDate AND @ToDate)
OR
(@Type<>'I' AND B.VoucherDate BETWEEN @FromDate AND @ToDate))
AND 
...

当然,正确的索引是如何加速查询的方式,如果InvoiceDate,VoucherDate等上没有索引,那么你的查询将使用全表扫描而不是索引搜索,它会很慢。