oracle merge 실행계획 문의 0 4 2,351

by 까막 [SQL Query] [2023.08.02 14:19:15]


11라인수정.png (35,658Bytes)

안녕하세요 구루비에서 많은 도움을 받고 있는 개발자입니다.

merge문을 작성하다보니 조건에 따라 실행계획이 다르게 나오는부분이 있어 궁금한사항이 있어서 문의드립니다.

 

1번

merge into a
using (select col, num from b where col = 'A') b
on (a.col = b.col)
when matched then update set a.num = b.num

 

2번

merge into a
using (select col, num from b where col = 'A') b
on (a.col = 'A')
when matched then update set a.num = b.num

 

b에 들어가는 쿼리의 결과값은 반드시 col이 A만 나오게됩니다.

이때 on에 들어가는 조건에

1번과 같이 b의 결과값을 대입하였을때와

2번과 같이 값을 명시적으로 입력하였을때와 실행결과가 다르게 나옵니다.

(2번과 같이 값을 명시적으로 입력하였을때가 더 성능이 좋음)

 

어떻게 생각해보면 오라클입장에서는

b의 결과값이 어떤게 나올지 예측할 수 없으므로

a의 테이블에 전체 서치해야하므로 성능이 안나오는게 맞을듯한데

2번과 같이 쿼리를 작성하는게 더 좋은 성능을 내는게 맞다고 이해하면 될까요~?,

by 마농 [2023.08.02 15:03:43]

실제 쿼리 맞나요? 뭔가 많이 생략된 느낌인데요?
보통 머지문의 조인조건은 1:1 로 매핑이 될텐데?
그렇다면 지금 제시된 쿼리는 1건짜리 업데이트 쿼리인데요.
1건짜리 쿼리가 성능차가 있다는게 좀 의아하네요.
실제 쿼리와 다른 쿼리로 질문하신 것은 아닌지?


by 까막 [2023.08.02 15:12:09]
안녕하세요 마농님
실제 쿼리는 아래와 같습니다 (테이블 및 데이터는 일부 조작,,)
최종적으로 merge되는 데이터는 약 5천건 정도입니다.

merge into A_202301 h                                                                                                                     
using                                                                                                                                              
(                                                                                                                                                  
    select                                                                                                                                         
        intervalanstimestamp,                                                                                                                      
        site as site,                                                                                                                              
        distribution_agtid,                                                                                                                        
        sum(case when distribution_agtid is not null then 1 else 0 end) as offer,                                                                  
        sum(case when agtid is not null then 1 else 0 end) as ans,                                                                                 
        sum(talktime) as talktime                                                                                                                  
    from                                                                                                                                           
    (                                                                                                                                              
        select                                                                                                                                     
            case when to_char(intervalanstimestamp, 'YYYY') = '0001' then intervaltimestamp else intervalanstimestamp end as intervalanstimestamp, 
            site as site,                                                                                                                          
            distribution_agtid,                                                                                                                    
            agtid,                                                                                                                                 
            talktime                                                                                                                               
        from B_202301                                                                                                                      
        where ymd = '20230102'                                                                                                                            
        and site = 'A'         
        union all                                                                                                                                  
        select                                                                                                                                     
            case when to_char(intervalanstimestamp, 'YYYY') = '0001' then intervaltimestamp else intervalanstimestamp end as intervalanstimestamp, 
            userdata20 as site,                                                                                                                    
            distribution_agtid,                                                                                                                    
            agtid,                                                                                                                                 
            talktime                                                                                                                               
        from B_202301                                                                                                                       
        where ymd = '20230102'                                                                                                                           
        and userdata20 = 'A'                      
    )                                                                                                                                              
    group by intervalanstimestamp, site, distribution_agtid                                                                                        
) c                                                                                                                                                
on (h.ymd = '20230104' and h.site = c.site and h.timestamp = c.intervalanstimestamp  and h.agtid = c.distribution_agtid) -- 성능이 떨어짐                           
on (h.ymd = '20230104' and h.site = 'A' and h.timestamp = c.intervalanstimestamp  and h.agtid = c.distribution_agtid)    -- 성능이 더 좋음                       
when matched then                                                                                                                                  
update set                                                                                                                                         
    h.offer = c.offer,                                                                                                                             
    h.ans = c.ans,                                                                                                                                 
    h.talktime = c.talktime,                                                                                                                       
    h.abd = c.offer - c.ans

 


by 마농 [2023.08.02 15:28:14]

질문의 쿼리는 원본과 많이 달랐네요.
이렇게 질문하시면 전혀 다른 질문이 되어 버립니다.
말이 안되는 질문이 될 수도 있구요.
실행계획도 보고 싶긴 하네요.

일단 성능이 좋은 쪽으로 가는게 맞을 듯 한데요.
h.site = c.site 조건을 그대로 사용하고 싶다면 다음과 같이 시도해 보는 것은 어떨까요?
11번째 라인을 다음과 같이 변경해 보면 어떨지?
- 변경전 : site AS site,
- 변경후 : 'A' AS site,


by 까막 [2023.08.02 17:18:00]

다음부터는 다소 복잡하더라도 원본쿼리로 문의드리는게 오해의 소지가없겠네요!

말씀하신대로 11번째 라인만바꼈을때도 실행계획이 바뀌는것을 확인했습니다.

실행계획말씀하셔서 파일도 첨부했습니다.

항상 많은 도움을 받습니다. 감사합니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입