2016-11-18 16 views
0

クエリの最初の部分は、PolicyPremiums,EffectiveおよびExpirationの日付を取得します。 2番目の部分はCalendarを作成し、3番目の部分(最終SELECT文)はMonthYearの順に分解されます。 すべて正常に動作し、結果を表示するのにわずか3秒かかります。 しかし、私はフィルタリングする必要がありますPolicyNumberは、基本的に私はPolicyNumberを取り除く必要があるのは@ClassCodeを持っていないです。だから私はWHERE句置かれ、クエリの最初の部分で、そのために:私はこの文を持っている@Prdpユーザにサブクエリを使用するときのクエリパフォーマンスを向上させる方法

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を:Caseステートメントは、他のNULLがなるリストに存在するClassCodeのための1を生成します生成される。カウント集計は、各PolicyNumberについて1をカウントします。 = 0を設定することで、PolicyNumberに指定されたリストにClassCodeが存在しないことを確認できます。

このクエリが永遠に回転した後、@ClassCodeはSSRSレポートで200 ClassCodes以上になる可能性があります。

興味深いことに、両方のステートメントが別々に正常に動作します。私は(それらを一緒に使用する場合でも、cte policy_dataWHERE節が実行は永遠に取るように配置されている。 は

; 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両方のテーブルのPolicyNumbernon-clusteredというインデックスを作成しました。しかし、まだ何も。 SQL Engineが3秒かかる最初の部分(PolicyNumberフィルタリング)を処理し、次にもう3秒かかる2番目の部分(それらのPolicyNumberの計算)を実行すると、それは素晴らしいと思われます。 しかし、私はDBAを初めて熟知しているので、その可能性についてもわかりません。 アドバイスはありますか? おかげ

実行計画::

enter image description here 最終結果:

enter image description here

+0

Codereview.stackexchange.comは 'tblClassCodesPlazaCommercial'が' NULL ClassCode'を持っているdoesntのこの – scsimon

答えて

0

あなたはあなたのコードを読みやすくするために持っています。 cteの代わりにtempテーブルを使用して小さなブロックに分割します。

あなたの悩み:

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

ClassCodeがあなたの持つHAVING COUNTで5000ある場合(TRUE - > 1)。

もしあなたの所持人数が(偽 - > NULL)のClassCodeが5151ならば、

がして、グループの前にフィルタリングする必要があります。

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

表のためのより良い場所です。 Tempテーブルで分割するとパフォーマンスが向上しますか? ありがとう – Oleg

+0

コードを分割すると読みやすくなり、実行計画がすぐに変更されます。パフォーマンスの問題がどこにあるか、qryが正しいデータを返さない場所で情報を取得する方が簡単です。 – Deadsheep39

関連する問題