Почему объединение двух табличных переменных значительно увеличивает время выполнения в SQL Server 2012 - PullRequest
0 голосов
/ 25 апреля 2018

Я извлекаю данные в две табличные переменные @PremiumData и @LossData.Присоединяемый столбец: ControlNo.

Если я запускаю их отдельно, время выполнения для заполнения @PremiumData составляет 3 секунды, а время выполнения для заполнения @LossData составляет 0 секунд.

Но когда я соединяю их вместе через left join, время выполнения увеличивается до 01:07!минут.

План запроса можно найти здесь: https://www.brentozar.com/pastetheplan/?id=Syd564Tnf

DECLARE
    @EffectiveDateFrom DATETIME = '2012-04-01',
    @EffectiveDateTo DATETIME = '2018-04-30'

DECLARE @PremiumData TABLE (
                            ControlNo int,
                            PolicyNumber varchar(50),
                            EffectiveDate datetime,
                            ExpirationDate datetime,
                            ProducerName varchar(300), 
                            Premium money
                           )
DECLARE @LossData TABLE (
                        ControlNo int,
                        Losses money
                        )

INSERT INTO @PremiumData
    SELECT 
        INV.QuoteControlNum,  
        tblQuotes.PolicyNumber,
        tblQuotes.EffectiveDate,
        (SELECT TOP 1 Q.ExpirationDate
         FROM tblQuotes Q
         WHERE Q.ControlNo = tblQuotes.ControlNo
         ORDER BY Q.QuoteID DESC) as ExpirationDate,
        tblProducers.ProducerName,
        (SELECT ISNULL(SUM(tblFin_InvoiceDetails.AmtBilled), 0)
         FROM tblFin_InvoiceDetails
         WHERE (tblFin_InvoiceDetails.ChargeType = 'P')
           AND (tblFin_InvoiceDetails.InvoiceNum = INV.InvoiceNum)) AS Premium
    FROM            
        tblFin_Invoices INV
    INNER JOIN      
        tblQuotes ON INV.QuoteID = tblQuotes.QuoteID
    INNER JOIN      
        tblProducerLocations ON INV.ProducerLocationGUID = tblProducerLocations.ProducerLocationGUID
    LEFT OUTER JOIN 
        tblProducers WITH (NOLOCK) ON tblProducerLocations.ProducerGUID = dbo.tblProducers.ProducerGUID 
    WHERE 
        (INV.Failed = 0)  
        AND (DATEDIFF(dd, tblQuotes.EffectiveDate, ISNULL(@EffectiveDateTo, tblQuotes.EffectiveDate)) >= 0)
        AND (DATEDIFF(dd, ISNULL(@EffectiveDateFrom, tblQuotes.EffectiveDate), tblQuotes.EffectiveDate) >= 0)
        AND dbo.tblQuotes.CompanyLocationGUID IN ('32828BB4-E1FA-489F-9764-75D8AF7A78F1',--"Plaza Insurance Company"    
                                                  '54A8FCCD-C7FE-4642-9C22-3A25207CDAEE' -- Watford         
                                                 )   

INSERT INTO @LossData
    SELECT 
        CPI.ControlNumber,
        SUM(CRP.ResPayAmount) as [Losses]
    FROM
        tblClaims_Claim C
    INNER JOIN 
        tblClaims_PolicyInformation CPI ON CPI.ClaimId = C.ClaimId
    INNER JOIN 
        tblClaims_ReservePayments CRP ON CRP.ClaimId = C.ClaimId
    GROUP BY
        CPI.ControlNumber--,

/* Joining @PremiumData and @LossData*/
SELECT  
    p.PolicyNumber,
    CONVERT(VARCHAR(11),p.EffectiveDate,101) as EffectiveDate,
    YEAR(EffectiveDate) as EffectiveYear,
    MONTH(EffectiveDate) as EffectiveMonth,
    SUBSTRING('JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC ', (MONTH(EffectiveDate) * 4) - 3, 3) as MonthShort,
    'Q' + CONVERT(CHAR(1),DATEPART(QUARTER, p.EffectiveDate)) as Quarter,
    p.ProducerName,
    SUM(p.Premium) as Premium,
    ISNULL(ROUND(dbo.fn_EarnedPremiumCalcExtendedPolicies(SUM(Premium), EffectiveDate, ExpirationDate, 0, GETDATE()), 2), SUM(Premium)) AS EarnedPremium,   
    ISNULL(l.Losses,0) as Losses,
    ISNULL(SUM(l.Losses), 0) / NULLIF(ISNULL(ROUND(dbo.fn_EarnedPremiumCalcExtendedPolicies(SUM(Premium), EffectiveDate, ExpirationDate, 0, GETDATE()), 2), SUM(Premium)),0) as LossRatio
FROM 
    @PremiumData p
LEFT JOIN 
    @LossData l ON p.ControlNo = l.ControlNo 
GROUP BY  --p.ControlNo
    p.PolicyNumber,
    p.EffectiveDate,
    p.ExpirationDate,
    p.ProducerName,
    l.Losses

Это также часть плана выполнения, которая касается меня:

enter image description here

1 Ответ

0 голосов
/ 25 апреля 2018

Посмотрите на примерное количество строк для ваших табличных переменных в плане выполнения, который вы связали. Оценки составляют 1 строку, но фактические строки намного выше.

Проблема в том, что оценка количества элементов далека. Я полагаю, что запрос вызывает утечку в временную базу данных, потому что начальное предоставление памяти слишком мало. Вот несколько полезных ответов здесь

Попробуйте использовать временные таблицы вместо табличных переменных.

Вы также можете попробовать добавить option(recompile) в конце ваших insert операторов (табличная переменная или временная таблица), и это должно улучшить ваши оценки количества элементов.

Правка на основе ваших правок: этот вид также страдает от плохой оценки мощности. Сортировка существует, потому что вы группируете запрос, где вы объединяете две табличные переменные.

...