with cte as
(select t.sid,
t.end_date,
t.nav,
t.d_value,
t.s_value,
t.factor,
t.rn,
cast(1 AS decimal(18, 8)) as pre_factor
from stg.etl_dg t
where t.rn = 1
union all
select t1.sid,
t1.end_date,
t1.nav,
t1.d_value,
t1.s_value,
t1.factor,
t1.rn,
cast(t1.factor * t2.pre_factor AS decimal(18, 8)) as pre_factor
from stg.etl_dg t1
join cte t2
on t1.sid = t2.sid
and t1.RN = t2.RN + 1)
select t3.sid,
t3.end_date,
t3.nav,
t3.d_value,
t3.s_value,
t3.factor,
t3.pre_factor
from cte t3 OPTION(MAXRECURSION 0)
/*
耗时>1h
*/
--表信息
select count(1) from stg.etl_dg --3124331
sp_helpindex 'stg.etl_dg' --NO INDEX
--减少测试数据量,方便查看优化效果
with cte as
(select t.sid,
t.end_date,
t.nav,
t.d_value,
t.s_value,
t.factor,
t.rn,
cast(1 AS decimal(18, 8)) as pre_factor
from stg.etl_dg t
where t.rn = 1
and t.rn <= 10 ---###
union all
select t1.sid,
t1.end_date,
t1.nav,
t1.d_value,
t1.s_value,
t1.factor,
t1.rn,
cast(t1.factor * t2.pre_factor AS decimal(18, 8)) as pre_factor
from stg.etl_dg t1
join cte t2
on t1.sid = t2.sid
and t1.RN = t2.RN + 1
and t1.rn <= 10 ---###
)
select t3.sid,
t3.end_date,
t3.nav,
t3.d_value,
t3.s_value,
t3.factor,
t3.pre_factor
from cte t3
/*
SQL Server parse and compile time:
CPU time = 4 ms, elapsed time = 4 ms.
(45278 行受影响)
Table 'Worktable'. Scan count 45280, logical reads 9863362, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'etl_dg'. Scan count 2, logical reads 56232, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 13344 ms, elapsed time = 13686 ms.
*/
--建立索引测试
CREATE NONCLUSTERED INDEX [idx_etl_dg_inc]
ON [stg].[etl_dg] ([RN])
INCLUDE ([sid],[end_date],[nav],[d_value],[s_value],[factor])
/*
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 4 ms.
(45278 行受影响)
Table 'Worktable'. Scan count 45280, logical reads 9926793, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'etl_dg'. Scan count 2, logical reads 26845, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 14891 ms, elapsed time = 15729 ms.
*/
--尝试改写SQL,测试优化效果不大
with cte as(
select t.sid,t.factor,t.rn,cast(1 AS decimal(18,8)) as pre_factor
from stg.etl_dg t
where t.rn = 1
and t.rn<=10 ---###
union all
select t1.sid,t1.factor,t1.rn,cast(t1.factor*t2.pre_factor AS decimal(18,8)) as pre_factor
from stg.etl_dg t1 join cte t2
on t1.sid = t2.sid
and t1.RN = t2.RN + 1
and t1.rn<=10 ---###
)
select t3.sid,t.end_date,t.nav,t.d_value,t.s_value,t3.factor,t3.pre_factor
from cte t3,stg.etl_dg t
where t3.RN=t.RN and t3.sid=t.sid
/*
--增加唯一约束
ALTER TABLE stg.etl_dg ADD CONSTRAINT etl_dg$BPK_AK_Key UNIQUE NONCLUSTERED(RN,sid) WITH(ONLINE=ON,FillFactor=90)
--增加字段返还索引
CREATE NONCLUSTERED INDEX idx_etl_dg_inc ON stg.etl_dg (RN) INCLUDE (sid,factor) WITH(ONLINE=ON,FillFactor=90)
*/
/*
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 8 ms.
(45278 行受影响)
Table 'Worktable'. Scan count 45280, logical reads 9831102, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'etl_dg'. Scan count 3, logical reads 27236, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 14453 ms, elapsed time = 15041 ms.
*/
--建立索引测试2
create clustered index etl_dg_asc on stg.etl_dg(sid, RN) WITH(ONLINE=ON,FillFactor=90)
--drop index etl_dg_asc on stg.etl_dg
/*
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
(45278 行受影响)
Table 'Worktable'. Scan count 2, logical reads 262902, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'etl_dg'. Scan count 45279, logical reads 136567, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 922 ms, elapsed time = 1518 ms.
*/
--最终优化效果
数据库变更:
create clustered index etl_dg_asc on stg.etl_dg(sid, RN) WITH(ONLINE=ON,FillFactor=90)
CREATE NONCLUSTERED INDEX idx_etl_dg_inc ON stg.etl_dg (RN) INCLUDE (sid,end_date,nav,d_value,s_value,factor) WITH(ONLINE=ON,FillFactor=90)
/*
SQL Server parse and compile time:
CPU time = 3 ms, elapsed time = 3 ms.
(3124331 行受影响)
Table 'Worktable'. Scan count 2, logical reads 18737220, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'etl_dg'. Scan count 3124332, logical reads 9421054, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 68734 ms, elapsed time = 91236 ms.
*/
--运行时长控制在一分半钟左右,逻辑读减少85%,时间减少95%+
--整个存储过程运行时间由45min+减少到3min以内