通过缓慢运行来调整组

时间:2016-07-19 08:02:34

标签: sql sql-server

对于具有350,000条记录的最大表PremiseProviderBillings的数据库,以下SQL需要5秒。但是在具有150万条记录的相同数据库上,它需要一分钟

SELECT
   n.CustomerInvoiceNumberId as InvoiceNo,C.CustomerBillId,c.customerid, S.Volumetric, S.Fixed, S.VAT, S.Discount, C.Debit,c.EffectiveDate,c.TransactionDateTime,s.Consumption,r.CustomerCreditNoteId--,s.Volumetric + s.Fixed + s.Vat - s.discount - c.debit as variance
FROM
  CustomerPayments C 
INNER JOIN
  (SELECT
     CustomerBillId, SUM(a.VolumetricCharge) as Volumetric,SUM(a.FixedCharge) as Fixed,
     SUM(a.VAT) as VAT,SUM(a.Discount) as Discount,sum(a.EstimatedConsumption) as Consumption
   FROM
     PremiseProviderBillings a, PremiseProviderBills b
    WHERE a.PremiseProviderBillId = b.PremiseProviderBillId
   GROUP BY
     CustomerBillId) S
ON
  C.CustomerBillId = S.CustomerBillId 
  and debit <> 0 -- hide credit note lines, we mark these results with customerCreditNoteId to show they have been credited
INNER JOIN dbo.CustomerInvoiceNumbers n on c.CustomerBillId = n.CustomerBillId
left OUTER JOIN
           dbo.CustomerCreditNotes AS r ON c.CustomerPaymentId = r.CustomerPaymentId
where isnull(c.transactionDateTimeEnd,'')=''

如果我然后运行内部SQL部分,它将较小数据库上的值相加,则需要2秒。在较大的数据库上需要34秒,内部SQL低于......

SELECT
     CustomerBillId, SUM(a.VolumetricCharge) as Volumetric,SUM(a.FixedCharge) as Fixed,
     SUM(a.VAT) as VAT,SUM(a.Discount) as Discount,sum(a.EstimatedConsumption) as Consumption
   FROM
     PremiseProviderBillings a, PremiseProviderBills b
    WHERE a.PremiseProviderBillId = b.PremiseProviderBillId
   GROUP BY
     CustomerBillId

很明显,这个SQL根本无法扩展。鉴于数据库将增长应该采用哪种技术来改善这一点?

我检查了所有连接,以确保没有丢失的索引,以确保所有连接都是基于密钥的,确定

我原本以为这种方法没问题,但是我应该改变SQL的结构,这是不可扩展且效率低的吗?

此致

2 个答案:

答案 0 :(得分:0)

尝试对内部查询使用公用表表达式,这可能会加快一些速度。

WITH CTE AS
(
    SELECT
         CustomerBillId, SUM(a.VolumetricCharge) as Volumetric,SUM(a.FixedCharge) as Fixed,
         SUM(a.VAT) as VAT,SUM(a.Discount) as Discount,sum(a.EstimatedConsumption) as Consumption
       FROM
         PremiseProviderBillings a, PremiseProviderBills b
        WHERE a.PremiseProviderBillId = b.PremiseProviderBillId
       GROUP BY
         CustomerBillId
)   

SELECT
   n.CustomerInvoiceNumberId as InvoiceNo,C.CustomerBillId,c.customerid, S.Volumetric, S.Fixed, S.VAT, S.Discount, C.Debit,c.EffectiveDate,c.TransactionDateTime,s.Consumption,r.CustomerCreditNoteId--,s.Volumetric + s.Fixed + s.Vat - s.discount - c.debit as variance
FROM
  CustomerPayments C 
INNER JOIN
  CTE S
ON
  C.CustomerBillId = S.CustomerBillId 
  and debit <> 0 -- hide credit note lines, we mark these results with customerCreditNoteId to show they have been credited
INNER JOIN dbo.CustomerInvoiceNumbers n on c.CustomerBillId = n.CustomerBillId
left OUTER JOIN
           dbo.CustomerCreditNotes AS r ON c.CustomerPaymentId = r.CustomerPaymentId
where isnull(c.transactionDateTimeEnd,'')=''

答案 1 :(得分:0)

如果您经常使用该查询,并且根据您写入表的频率,可能值得为此创建indexed view。然而值得注意的是,这是猜测,并且索引视图确实带来了折衷,您的读取速度会更快但写入速度会更慢。

CREATE VIEW dbo.CustomerBillingView
WITH SCHEMABINDING
AS
    SELECT  b.CustomerBillId,
            SUM(a.VolumetricCharge) AS Volumetric,
            SUM(a.FixedCharge) AS Fixed,
            SUM(a.VAT) AS VAT,
            SUM(a.Discount) AS Discount,
            SUM(a.EstimatedConsumption) AS Consumption,
            COUNT_BIG(*) AS Records -- REQUIRED TO CREATE INDEX
    FROM    dbo.PremiseProviderBillings a
            INNER JOIN dbo.PremiseProviderBills b
                ON a.PremiseProviderBillId = b.PremiseProviderBillId
    GROUP BY b.CustomerBillId;
GO

CREATE UNIQUE CLUSTERED INDEX UQ_CustomerBillingView__CustomerBillId
    ON dbo.CustomerBillingView (CustomerBillId);

GO

然后,您只需要使用提示NOEXPAND的视图来确保使用索引。

SELECT  n.CustomerInvoiceNumberId as InvoiceNo,
        c.CustomerBillId,
        c.customerid, 
        s.Volumetric, 
        s.Fixed, 
        s.VAT, 
        s.Discount, 
        c.Debit,
        c.EffectiveDate,
        c.TransactionDateTime,
        s.Consumption,
        r.CustomerCreditNoteId
        --,s.Volumetric + s.Fixed + s.Vat - s.discount - c.debit as variance
FROM    CustomerPayments AS c 
        INNER JOIN dbo.CustomerBillingView AS s WITH (NOEXPAND)
            ON c.CustomerBillId = s.CustomerBillId 
            AND c.Debit <> 0 
            -- hide credit note lines, we mark these results with customerCreditNoteId to show they have been credited
        INNER JOIN dbo.CustomerInvoiceNumbers n 
            ON c.CustomerBillId = n.CustomerBillId
        LEFT OUTER JOIN dbo.CustomerCreditNotes AS r 
            ON c.CustomerPaymentId = r.CustomerPaymentId
WHERE   ISNULL(c.transactionDateTimeEnd,'') = '';

与每个查询调优问题一样,您是唯一拥有正确回答所需信息的人。 根据我的经验(主要在计费系统中),像这样的索引视图通常可以使用结算数据,因为大多数发票运行都是周期性的, 所以写入是批量而不是连续的,并且读取也往往超过写入,因为数据是静态的,一旦创建了发票然后它 很少更新。