查询的第一部分会抓取Policy
的{{1}},Premiums
和Effective
日期。
第二部分创建Expiration
,第三部分(最终Calendar
声明)返回按SELECT
和Month
细分的收入
一切正常,只需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的新手,所以我不确定它是否可能。
有什么建议?
感谢
执行计划::
答案 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