每天都有时间表表,许多客户都会在此表中插入时间表表, 表结构会像这样
Create table factSchedule (factID bigint identity (1,1) primary key, custId char(10), scheduleDate date, amount money, LoadedOn date)
说,
每个客户将有100多个时间表条目
每天将有10,000个客户插入相应的计划条目
此表将通过插入更新的计划条目进行每日更新,例如,对于第一个loadingOn日期,将有100条客户记录,而在第二loadedOn日期,将有100条记录,但金额不同,因此最终会有〜两天内为一位客户提供200条记录,因此您可以想象这张桌子有多大...
现在,我有一个SP,它将根据factSchedule表中给定输入日期的第一个scheduleDate返回一些计算出的存储桶字段。所以首先我需要一个cte表,该表仅包含给定LoadedOn字段的每个custId的第一个计划日期,作为输入参数,如下所示;
;with cteSchedule as
( SELECT result.*
(select custId, scheduleDate, Amount,@inputDate as compareDate, row_number ()over ( partition by loadedon, custId order by loadedon, custId, scheduleDate)rownum From factSchedule Where LoadedOn = @inputDate and scheduleDate >= @ inputDate)
) as result
WHERE result.rownum = 1
现在我还有另一个表叫做Customertable,该表将为每个custId都有一个记录,因此该表中大约有10,000个客户。
所以我的SP在这里,
;with cteSchedule as
( SELECT result.*
(select custId, scheduleDate, Amount,@inputDate as compareDate, row_number ()over ( partition by loadedon, custId order by loadedon, custId, scheduleDate)rownum From factSchedule Where LoadedOn = @inputDate and scheduleDate >= @ inputDate)
) as result
WHERE result.rownum = 1
Select Maintable.CustID,
(select case when scheduleDate < dateadd (day,7,compareday)
then ‘Customertable.someAmount ’
Else 0 end
From factSchedule and cteSchedule.custId = Maintable.custId) end as
Amt_0to7_days,
(select case when ScheduleDate >= DATEADD (DAY,7,compareday) AND ScheduleDate <= DATEADD (MONTH,1,compareday)
then ‘Customertable.someAmount’
Else 0 end
From factSchedule and cteSchedule.custId = Maintable.custId) end as
Amt_7to30_days,
(select case when ScheduleDate >= DATEADD (MONTH,1,compareday) AND ScheduleDate <= DATEADD (MONTH,3,compareday)
then ‘Customertable.someAmount’
Else 0 end
From factSchedule and cteSchedule.custId = Maintable.custId) end as
Amt_1to3_Months,
-- "like wise it will have another five buckets."
From Customertable
以下是此SP的执行计划,它显示了我的第一个cteSchedule表中的Sort运算符为每个存储桶收取10%的查询成本,因此总共有8个存储桶,将有80%的查询成本,这导致了很多时间(超过1小时)。另外,排序运算符中的警告标志(操作员在执行门槛级别1时使用tempDb溢出数据)又意味着什么?
是否还有其他方法可以减少这种排序运算符的查询成本,还是可以重写逻辑?无论如何,帮助将不胜感激。提前感谢
实际代码:
declare @RunDateLocal date = '20180709'
;with cteSchedule AS
(SELECT schedule.*
FROM (select ContractIDKey,ScheduleDateKey, @RunDateLocal as compareDay,row_number ()over ( partition by loadedon,ContractIDKey order by loadedon,ContractIDKey,ScheduleDateKey)rownum
from FactSchedules
where LoadedOn = DATEADD(D,1,@RunDateLocal) and ScheduleDateKey>= @RunDateLocal) as schedule
WHERE schedule.rownum = 1
)
select FB.ContractIDKey,
(select case when ScheduleDateKey < DATEADD (DAY,7,compareday)
Then ISNULL(AIA.Closingbalance,0)
else 0 end
from cteschedule where rownum = 1 and cteSchedule.ContractIDKey = FB.ContractIDKey) as Interest_0To7_Days,
(select case when ScheduleDateKey >= DATEADD (DAY,7,compareday) AND ScheduleDateKey <= DATEADD (MONTH,1,compareday)
Then ISNULL(AIA.Closingbalance,0)
else 0 end
from cteschedule where rownum = 1 and cteSchedule.ContractIDKey = FB.ContractIDKey) as Interest_7To30_Days,
(select case when ScheduleDateKey > DATEADD (MONTH,1,compareday) AND ScheduleDateKey <= DATEADD (MONTH,3,compareday)
Then ISNULL(AIA.Closingbalance,0)
else 0 end
from cteschedule where rownum = 1 and cteSchedule.ContractIDKey = FB.ContractIDKey) as Interest_1To3_Months,
(select case when ScheduleDateKey > DATEADD (MONTH,3,compareday) AND ScheduleDateKey <= DATEADD (MONTH,6,compareday)
Then ISNULL(AIA.Closingbalance,0)
else 0 end
from cteschedule where rownum = 1 and cteSchedule.ContractIDKey = FB.ContractIDKey) as Interest_3To6_Months,
(select case when ScheduleDateKey > DATEADD (MONTH,6,compareday) AND ScheduleDateKey <= DATEADD (MONTH,12,compareday)
Then ISNULL(AIA.Closingbalance,0)
else 0 end
from cteschedule where rownum = 1 and cteSchedule.ContractIDKey = FB.ContractIDKey) as Interest_6To12_Months,
(select case when ScheduleDateKey > DATEADD (YEAR,1,compareday) AND ScheduleDateKey <= DATEADD (YEAR,3,compareday)
Then ISNULL(AIA.Closingbalance,0)
else 0 end
from cteschedule where rownum = 1 and cteSchedule.ContractIDKey = FB.ContractIDKey) as Interest_1To3_Years,
(select case when ScheduleDateKey > DATEADD (YEAR,3,compareday) AND ScheduleDateKey <= DATEADD (YEAR,5,compareday)
Then ISNULL(AIA.Closingbalance,0)
else 0 end
from cteschedule where rownum = 1 and cteSchedule.ContractIDKey = FB.ContractIDKey) as Interest_3To5_Years,
(select case when ScheduleDateKey > DATEADD (YEAR,5,compareday)
Then ISNULL(AIA.Closingbalance,0)
else 0 end
from cteschedule where rownum = 1 and cteSchedule.ContractIDKey = FB.ContractIDKey) as Interest_5Over_years
from FactBalances FB
LEFT JOIN vAllDeposists_AIAAmount AIA ON AIA.ContractIDKey = FB.ContractIDKey
答案 0 :(得分:1)
您是否尝试过在临时表中实现数据集而不是使用CTE?公用表表达式将在每次使用sql时运行sql,而临时表将仅运行一次并重用相同的结果集。这种方法应该减少排序的数量(减少到1)。
泄漏通常与不良数据有关。检查估计的执行计划与实际的执行计划,以确认这一点。放弃cte也可以提供帮助,因为可以重建统计信息。不用戳很难确定。
答案 1 :(得分:1)
对于cte中的查询,由于LoadedOn
始终相同,因此无需按该列进行分区或排序。另外,当按ContractIDKey
进行分区时,不需要按该列排序。
无需查询CTE或临时表8次。您用于原始cte的查询确实确实只返回ContractIDKey
1条记录,因此(外部)加入cte一次就足够了。我建议测试这样的查询(使用cte或临时表):
DECLARE @RunDateLocal date = '20180709';
WITH cteSchedule AS
(SELECT ContractIDKey, ScheduleDateKey
FROM (select ContractIDKey, ScheduleDateKey, row_number() over (partition by ContractIDKey ORDER BY ScheduleDateKey) rownum
from FactSchedules
where LoadedOn = DATEADD(D,1,@RunDateLocal) and ScheduleDateKey>= @RunDateLocal) as schedule
WHERE schedule.rownum = 1
)
SELECT
FB.ContractIDKey,
case
when cte.ScheduleDateKey < DATEADD(DAY,7,@RunDateLocal)
then ISNULL(AIA.Closingbalance, 0)
else 0
end as Interest_0To7_Days,
case
when cte.ScheduleDateKey >= DATEADD(DAY,7,@RunDateLocal) AND ScheduleDateKey <= DATEADD(MONTH,1,@RunDateLocal)
then ISNULL(AIA.Closingbalance,0)
else 0
end as Interest_7To30_Days,
case
when ScheduleDateKey > DATEADD(MONTH,1,@RunDateLocal) AND ScheduleDateKey <= DATEADD(MONTH,3,@RunDateLocal)
then ISNULL(AIA.Closingbalance,0)
else 0
end as Interest_1To3_Months,
case
when ScheduleDateKey > DATEADD(MONTH,3,@RunDateLocal) AND ScheduleDateKey <= DATEADD(MONTH,6,@RunDateLocal)
then ISNULL(AIA.Closingbalance,0)
else 0 end Interest_3To6_Months,
case
when ScheduleDateKey > DATEADD(MONTH,6,@RunDateLocal) AND ScheduleDateKey <= DATEADD(MONTH,12,@RunDateLocal)
then ISNULL(AIA.Closingbalance,0)
else 0
end as Interest_6To12_Months,
case
when ScheduleDateKey > DATEADD(YEAR,1,@RunDateLocal) AND ScheduleDateKey <= DATEADD(YEAR,3,@RunDateLocal)
then ISNULL(AIA.Closingbalance,0)
else 0
end as Interest_1To3_Years,
case
when ScheduleDateKey > DATEADD(YEAR,3,@RunDateLocal) AND ScheduleDateKey <= DATEADD(YEAR,5,@RunDateLocal)
then ISNULL(AIA.Closingbalance,0)
else 0
end as Interest_3To5_Years,
case
when ScheduleDateKey > DATEADD(YEAR,5,@RunDateLocal)
then ISNULL(AIA.Closingbalance,0)
else 0
end as Interest_5Over_years
FROM FactBalances FB
LEFT JOIN cteSchedule cte ON cte.ContractIDKey = FB.ContractIDKey
LEFT JOIN vAllDeposists_AIAAmount AIA ON AIA.ContractIDKey = FB.ContractIDKey