2016-11-18 2 views
0

Первая часть запроса захватывает Policy's Premiums, Effective и Expiration. Вторая часть создает Calendar, а третья часть (окончательная SELECT заявление) возвращает прибыль, деактивированная Month и Year Все работает нормально, занимает всего 3 секунды, чтобы отобразить результат. Но тогда мне нужно отфильтровать то, что PolicyNumber s для работы, в основном мне нужно избавиться от PolicyNumber, у которого нет @ClassCode. Так что в первой части запроса я поместил WHERE пункт:Как повысить производительность запроса при использовании подзапроса

WHERE State IN ('CA','NV','AZ')   
     AND PolicyNumber IN (
          SELECT PolicyNumber 
          FROM tblClassCodesPlazaCommercial 
          GROUP BY PolicyNumber 
          HAVING COUNT (CASE WHEN ClassCode NOT IN (@ClassCode)                  
THEN 1 END)=0 
          ) 

Thanksful для @Prdp пользователя У меня есть это заявление: Дело заявление будет генерировать 1 для ClassCode, который присутствует в списке еще NULL будет генерироваться. Теперь суммарный счетчик будет составлять 1 для каждого PolicyNumber. Установив = 0, мы можем убедиться, что PolicyNumber не содержит ClassCode в данном списке.

После этого запроса, вращающегося навсегда, becase @ClassCode может иметь больше, чем 200 ClassCodes в отчете SSRS.

Интересные вещи в том, что оба эти заявления работают отлично. Но когда я использую их вместе (который помещается что WHERE положение в cte policy_data то выполнение принимает навсегда. Есть ли способ сказать двигатель, чтобы сделать первую часть запроса, которая

; WITH Earned_to_date AS (
    SELECT Cast(EOMONTH (GETDATE(), -1) AS DATE) AS Earned_to_date 
), policy_data AS (
    SELECT 
     PolicyNumber 
,  Cast(PolicyEffectiveDate AS DATE) AS PolicyEffectiveDate 
,  Cast(PolicyExpirationDate AS DATE) AS PolicyExpirationDate 
,  WrittenPremium 
,  State 
     FROM PlazaInsuranceWPDataSet 
     WHERE State IN ('CA','NV','AZ') 
    /* -------This statement gives me trouble ----------------------*/ 
     AND PolicyNumber IN (
          SELECT PolicyNumber 
          FROM tblClassCodesPlazaCommercial 
          GROUP BY PolicyNumber 
          HAVING COUNT (CASE WHEN ClassCode NOT IN (5151)                  
THEN 1 END)=0 
          ) 
) 

А затем рассчитать и разрыв вниз Прибыль только те политики, которые были отфильтрованы

Мой весь код ниже:.

; WITH Earned_to_date AS (
    SELECT Cast(EOMONTH (GETDATE(), -1) AS DATE) AS Earned_to_date 
), policy_data AS (
    SELECT 
     PolicyNumber 
,  Cast(PolicyEffectiveDate AS DATE) AS PolicyEffectiveDate 
,  Cast(PolicyExpirationDate AS DATE) AS PolicyExpirationDate 
,  WrittenPremium 
,  State 
     FROM PlazaInsuranceWPDataSet 
     WHERE State IN ('CA','NV','AZ') 
    /* -------This statement gives me trouble ----------------------*/ 
     AND PolicyNumber IN (
          SELECT PolicyNumber 
          FROM tblClassCodesPlazaCommercial 
          GROUP BY PolicyNumber 
          HAVING COUNT (CASE WHEN ClassCode NOT IN (@ClassCode)                  
THEN 1 END)=0 
          ) 
) 
, digits AS (
SELECT digit 
    FROM (VALUES (0), (1), (2), (3), (4) 
,  (5), (6), (7), (8), (9)) AS z2 (digit) 
), numbers AS (
SELECT 1000 * d4.digit + 100 * d3.digit + 10 * d2.digit + d1.digit AS number 
    FROM digits AS d1 
    CROSS JOIN digits AS d2 
    CROSS JOIN digits AS d3 
    CROSS JOIN digits AS d4 
), calendar AS (
SELECT 
    DateAdd(month, number, '1753-01-01') AS month_of 
, DateAdd(month, number, '1753-02-01') AS month_after 
    FROM numbers 
), policy_dates AS (
SELECT 
    PolicyNumber 
, CASE 
     WHEN month_of < PolicyEffectiveDate THEN PolicyEffectiveDate 
     ELSE month_of 
    END AS StartRiskMonth 
, CASE 
     WHEN PolicyExpirationDate < month_after THEN PolicyExpirationDate 
     WHEN Earned_to_date.Earned_to_date < month_after THEN Earned_to_date 
     ELSE month_after 
    END AS EndRiskMonth 
, DateDiff(day, PolicyEffectiveDate, PolicyExpirationDate) AS policy_days 
, WrittenPremium 
    FROM policy_data 
    JOIN calendar 
     ON (policy_data.PolicyEffectiveDate < calendar.month_after 
     AND calendar.month_of < policy_data.PolicyExpirationDate) 
    CROSS JOIN Earned_to_date 
    WHERE month_of < Earned_to_date 
) 
SELECT  
      Year(StartRiskMonth) as YearStartRisk, 
      Month(StartRiskMonth) as MonthStartRisk, 
      c.YearNum,c.MonthNum, 
      convert(varchar(7), StartRiskMonth, 120) as RiskMonth, 
      sum(WrittenPremium * DateDiff(day, StartRiskMonth, EndRiskMonth)/policy_days) as EarnedPremium 
FROM  tblCalendar c 
      LEFT JOIN policy_dates l ON c.YearNum=Year(l.StartRiskMonth) AND c.MonthNum = Month(l.StartRiskMonth) 
      AND l.StartRiskMonth BETWEEN '01-01-2015' AND '12-31-2016' 
WHERE  c.YearNum Not IN (2017) 
GROUP BY convert(varchar(7), StartRiskMonth, 120), 
      Year(StartRiskMonth) , Month(StartRiskMonth), 
      c.YearNum,c.MonthNum 
ORDER BY c.YearNum,c.MonthNum 

что бы быть лучшим способом для повышения производительности? 10 Я создал non-clustered индекс на PolicyNumber на обеих таблицах. Но все равно ничего. Как я уже сказал, мне кажется, что если SQL Engine обработает первую часть (фильтрация PolicyNumber), которая занимает 3 секунды, а затем сделать вторую часть (расчет для тех PolicyNumber), которая занимает еще 3 секунды - это было бы потрясающе. Но я новичок в DBA, поэтому я не уверен, что это даже возможно. Любые советы? Благодаря

Execution Plan ::

enter image description here Конечный результат:

enter image description here

+0

Codereview.stackexchange.com является лучшим местом для этого – scsimon

ответ

0

Вы должны сделать код более читаемым. Разделите его на меньшие блоки с помощью временных таблиц вместо cte.

Ваша беда:

HAVING COUNT (CASE WHEN ClassCode NOT IN (5151) THEN 1 END)=0 

Если ClassCode 5000 в вашем имея HAVING COUNT (TRUE -> 1).

Если ClassCode имеет значение 5151, у вас есть HUNING COUNT (FALSE -> NULL).

следует фильтровать перед группой по:

WHERE ClassCode IN (5151) -- and check index 
+0

таблицы 'tblClassCodesPlazaCommercial' Не должен' NULL ClassCode'. Так будет ли производительность улучшаться, если я сломаю ее по таблицам Temp? Спасибо – Oleg

+0

Когда вы разделите код, он будет более читабельным и вы быстро измените план выполнения - вам будет гораздо проще получить информацию о ваших проблемах с производительностью или когда ваш qry не вернет правильные данные. – Deadsheep39

Смежные вопросы