如何在使用子查询时提高查询性能

时间:2016-11-18 23:01:59

标签: sql sql-server tsql join reporting-services

查询的第一部分会抓取Policy的{​​{1}},PremiumsEffective日期。 第二部分创建Expiration,第三部分(最终Calendar声明)返回按SELECTMonth细分的收入 一切正常,只需3秒即可显示结果。 但是我需要过滤Year要使用的内容,基本上我需要摆脱没有PolicyNumber的{​​{1}}。因此,对于查询的第一部分,我放置了PolicyNumber子句:

@ClassCode

感谢@Prdp用户我有这样的陈述:Case语句将为列表中存在的ClassCode生成1,否则将生成NULL。现在,每个PolicyNumber的count聚合将计为1。通过设置= 0,我们可以确保PolicyNumber在给定列表中没有任何ClassCode。

在该查询永远消失之后,因为WHERE在SSRS报告中可以有超过200 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 )

有趣的是,这两种说法都可以单独运作。但是当我一起使用它们(在@ClassCode中放置ClassCodes子句时,执行将永远执行。 有没有办法告诉引擎做查询的第一部分,即

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 索引。但仍然没有。 就像我说的,在我看来,如果SQL引擎将处理第一部分(PolicyNumber过滤)需要3秒,然后再执行第二部分(计算那些PolicyNumber&#39; s)需要另外3秒 - 这将是真棒。 但我是DBA的新手,所以我不确定它是否可能。 有什么建议? 感谢

执行计划::

enter image description here 最终结果:

enter image description here

1 个答案:

答案 0 :(得分:0)

您必须使代码更具可读性。通过临时表而不是cte将其拆分为更小的块。

你的麻烦:

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

如果您的HCOING COUNT(TRUE - > 1)中的ClassCode为5000。

如果您的HCOING COUNT(FALSE - &gt; NULL)中的ClassCode为5151。

应在分组前过滤:

WHERE ClassCode IN (5151) -- and check index