2017-03-28 4 views
0

재귀 CTE에서 처리 할 수 ​​있지만 허용 가능한 시간 내에 처리 할 수없는 문제가 있습니다. 누구든지 성능을 향상시키고 동일한 결과를 다른 방식으로 얻는 방법으로 나를 지적 할 수 있습니까?Oracle에서 날짜 범위의 값 계산 가능 (재귀 CTE 사용)

내 시나리오는 다음과 같습니다.

다음과 같은 정보가 있습니다. 각 행에 ID, 시작 날짜, 종료 날짜 및 순위 번호가 포함 된 큰 테이블. 각 ID에는 여러 행이 있으며 날짜 범위는 종종 겹칩니다. 날짜는 2010 년 이후입니다.

내가 원하는 것 : 이전 표의 해당 ID에 대한 날짜 범위 안에 속하는 id + date의 각 조합에 대한 행을 포함하는 표. 각 행은 해당 id 및 day에 대해 가장 낮은 순위 번호를 가져야합니다.

예 :

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분 (끔찍 표 3,100 만 행) :

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

테이블에서 가능한 모든 날짜를 한 번 추출 할 수 있습니다

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. 

열팽창 계수가 어떤 ID의 가장 높은 단계의 모든 ID에 대해 가장 낮은에서 모든 날짜를 가져옵니다 CTE는 다음 테이블이 다시 가입 할 수 있습니다. 테이블이 두 번있는 경우를 제외하고 정적 달력 테이블을 사용할 수도 있습니다 (최소/최대 버전은 동시에 일부 버전에서는 느려집니다).

는 또한으로, 라운드 그것을 다른 방법을 쓸 수있다 :

... 
from big_base_table bbt 
join all_dates ad 
on ad.day >= bbt.start_date 
and ad.day <= bbt.end_date 
... 

하지만 난 optimisier은 아마 당신의 기본 테이블의 단일 전체 검사와 함께, 그들에게 같은 치료를 끝낼 것이라고 생각; 계획을 점검할만한 가치가 있습니다. 실제로 계획안을 확인해보십시오.

+0

정적 캘린더 테이블을 사용하더라도 유감스럽게도 속도가 훨씬 느립니다. (나는 2 시간에 질의를 중단했다.) –

+0

전에 20 분이 걸렸던 동일한 작은 데이터 세트에서? 관심이 없으면 몇 개의 행이 있는지, 최소/최대 날짜를 찾는 데는 얼마나 걸리나요? (예 : CTE의 검색어 만 실행), 전반적인 기간은 얼마나됩니까? 이것에 대한 실행 계획은 너무 복잡 할 것입니다. –

+0

그래, 같은 거. ~ 5600 만 행이 있고 2010 년에서 2016 년까지의 7 년을 다룹니다. 달력이 구체화되고 색인이 생성되면서 설명 계획 (oops, 여기에서 편집 됨)은이 주석에 비해 너무 길지만 big_base_table에 대한 전체 테이블 액세스, 정렬 조인 , 필터링, 3365M 행을 가질 것이라고 생각하는 캘린더 테이블에 병합 (병합하지 않을 것입니다!), 다음 해시 그룹을 사용하십시오. 나는 그룹을 거치지 않고 달력 + 기본 조인을 실현하려고 시도했지만 단지 5 천 8 백만 행에 불과했습니다. –