我遇到的问题可以通过递归CTE处理,但不能在可接受的时间段内处理。任何人都可以指出我提高性能和/或以不同方式获得相同结果的方法吗?
这是我的情景!
我有:一个大表,每行包含一个id,一个开始日期,一个结束日期和一个排名编号。每个id有多行,日期范围经常重叠。日期从2010年开始。
我想:一个表,其中包含id + date的每个组合的行,该行位于上一个表中该id的任何日期范围内。每行应该具有该ID和日期的最低排名数。
例如:
ID Rank Range
1 1 1/1/2010-1/4/2010
1 2 1/2/2010-1/5/2010
2 1 1/1/2010-1/2/2010
变为
ID Rank Day
1 1 1/1/2010
1 1 1/2/2010
1 1 1/3/2010
1 1 1/4/2010
1 2 1/5/2010
2 1 1/1/2010
2 1 1/2/2010
我可以通过递归CTE来实现这一点,但性能非常糟糕(相对较小的数据集需要20-25分钟才能产生3100万行的最终表格):
with enc(PersonID, EncounterDate, EndDate, Type_Rank) as (
select PersonID, EncounterDate, EndDate, Type_Rank
from Big_Base_Table
union all
select PersonID, EncounterDate + 1, EndDate, Type_Rank
from enc
where EncounterDate + 1 <= EndDate
)
select PersonID, EncounterDate, min(Type_Rank) Type_Rank
from enc
group by PersonID, EncounterDate
;
答案 0 :(得分:0)
您可以在CTE中从表格中提取所有可能的日期,然后将其加入表格中:
with all_dates (day) as (
select start_date + level - 1
from (
select min(start_date) as start_date, max(end_date) as end_date
from big_base_table
)
connect by level <= end_date - start_date + 1
)
select bbt.id, min(bbt.type_rank) as type_rank, to_char(ad.day, 'YYYY-MM-DD') as day
from all_dates ad
join big_base_table bbt
on bbt.start_date <= ad.day
and bbt.end_date >= ad.day
group by bbt.id, ad.day
order by bbt.id, ad.day;
ID TYPE_RANK DAY
---------- ---------- ----------
1 1 2010-01-01
1 1 2010-01-02
1 1 2010-01-03
1 1 2010-01-04
1 2 2010-01-05
2 1 2010-01-01
2 1 2010-01-02
7 rows selected.
CTE从任何ID的最低日期获取所有日期,直至任何ID的最高日期。如果你有一个静态日历表,你也可以使用静态日历表来保存两次表(并且至少在某些版本中同时获得最小值/最大值)。
你也可以反过来写,如:
...
from big_base_table bbt
join all_dates ad
on ad.day >= bbt.start_date
and ad.day <= bbt.end_date
...
但我认为优化者可能最终会对它们进行相同的处理,只需对基表进行一次完整扫描;值得检查它实际上为两者提出的计划,如果一个比另一个更有效。