2013-12-17 4 views
0

명백한 성능상의 이유로 "in"절이 포함 된 상관 하위 쿼리를 포함하는 기존 Oracle SQL 쿼리를 다시 작성하고 싶습니다. 외부 조인 또는 다른 기술을 통해이 작업을 수행 할 수 있습니까?"in in"절을 사용하여 상관 관계가있는 부속 쿼리 다시 작성

SELECT TRIM(et.event_id), TRIM(et.cancel_evt_id) 
FROM external_transactions et 
JOIN transaction_type tt 
    ON et.transaction_type_id = tt.transaction_type_id 
WHERE et.acct = 'ABCDEF' 
AND tt.transaction_type_class != 'XYZXYZ' 
AND 
(
    TRIM(et.event_id) NOT IN 
     (
     SELECT TRIM(t1.transaction_evt_id) 
     FROM transactions t1 
     WHERE t1.acct = et.acct 
     AND t1.asset_id = et.asset_id 
     AND t1.cancel_flag = 'N' 
     ) 
    OR TRIM(et.cancel_evt_id) NOT IN 
     (
     SELECT TRIM(t2.cancel_evt_id) 
     FROM transactions t2 
     WHERE t2.acct = et.acct 
     AND t2.asset_id = et.asset_id 
     AND t2.cancel_flag = 'Y' 
     ) 
) 
; 
+2

"분명한 이유"는 무엇입니까? id에'trim() '을 사용하면 질의가 덜 효율적이게된다고 생각됩니다. –

+0

실행 계획을 게시하십시오. –

+0

왼쪽 조인을 수행하고 열의 WHERE IS NULL을 적용하는 것은 대개 훨씬 빠릅니다. 그러나, 그 말은 ... "et.event_id"및 "t1.transaction_evt_id"의 ​​실제 데이터 유형은 무엇입니까? 숫자 일 경우, TRIM()을 수행하는 것은 Gordon이 말한 것처럼 좋지 않습니다. – DRapp

답변

0

,이 가정 당신의 "ID"열이 정수를 기반으로하지 문자열을하지 않습니다 그들을 변환하십시오. 쿼리를 최적화 할 수 있도록 또한

, 난 당신이 트랜잭션 테이블이

Transactions (acct, asset_id, cancel_flag, transaction_evt_id, cancel_evt_id) 

과에 인덱스가 있다면 당신은 조금이라도 혜택을 누릴 수

External_Transactions (acct, event_id, cancel_evt_id) 
Transaction_Type (transaction_type_id, transaction_type_class) 
Transactions (transaction_evt_id, acct, asset_id, cancel_flag) 
Transactions (cancel_evt_id, acct, asset_id, cancel_flag) 


SELECT 
     et.event_id, 
     et.cancel_evt_id 
    FROM 
     external_transactions et 
     JOIN transaction_type tt 
      ON et.transaction_type_id = tt.transaction_type_id 
      AND tt.transaction_type_class != 'XYZXYZ' 
     LEFT OUTER JOIN transactions t1 
      ON et.event_id = t1.transaction_evt_id 
      AND et.acct = t1.acct 
      AND et.asset_id = t1.asset_id 
      AND t1.cancel_flag = 'N' 
     LEFT OUTER JOIN transactions t2 
      ON et.cancel_evt_id = t2.cancel_evt_id 
      AND et.acct = t2.acct 
      AND et.asset_id = t2.asset_id 
      AND t2.cancel_flag = 'Y' 
    WHERE 
      et.acct = 'ABCDEF' 
     AND ( t1.transaction_evt_id IS NULL 
      OR t2.cancel_evt_id IS NULL) 

인덱스가 보장 것이다 왼쪽 조인 같았습니다

SELECT 
     et.event_id, 
     et.cancel_evt_id 
    FROM 
     external_transactions et 
     JOIN transaction_type tt 
      ON et.transaction_type_id = tt.transaction_type_id 
      AND tt.transaction_type_class != 'XYZXYZ' 
     LEFT OUTER JOIN transactions t1 
      ON et.acct = t1.acct 
      AND et.asset_id = t1.asset_id 
      AND ( 
        ( t1.cancel_flag = 'N' 
        AND et.event_id = t1.transaction_evt_id) 
       OR 
        ( t1.cancel_flag = 'Y' 
        AND et.cancel_event_id = t1.cancel_evt_id) 
       ) 
    WHERE 
      et.acct = 'ABCDEF' 
     AND t1.transaction_evt_id IS NULL 

두 경우 모두 인덱스가 커버링 인덱스가되어 ha가되지 않았습니다. 레코드의 다른 요소를 확인하기 위해 원시 데이터 페이지로 돌아가십시오.

+0

DRapp를 사용하면 첫 번째 솔루션이 트릭을 수행하는 것으로 보입니다. Oracle Explain Plan 비용 견적은 315430에서 8715로 줄었습니다. 새 쿼리가 올바른 결과를 반환하는지 아직 테스트 중이지만 아직 테스트 조건을 찾지 못했습니다. – ptc3

+0

그리고 여러 사람들의 제안에 따라 trim() 함수가 논리적으로 필요한지 여부를 조사 할 것입니다. – ptc3

+0

@ ptc3, 다행 했어.하지만 시간이 지남에 따라 전반적인 성능 개선이 궁금하다. – DRapp

0

NOT EXISTS을 사용하여 : : 여기

코드입니다

을 제외하고 코멘트에서
SELECT TRIM(et.event_id), TRIM(et.cancel_evt_id) 
FROM external_transactions et 
JOIN transaction_type tt 
    ON et.transaction_type_id = tt.transaction_type_id 
WHERE et.acct = 'ABCDEF' 
AND tt.transaction_type_class != 'XYZXYZ' 
AND NOT EXISTS 
     (
     SELECT 1 
     FROM transactions t1 
     WHERE t1.acct = et.acct 
     AND t1.asset_id = et.asset_id 
     AND (( t1.cancel_flag = 'N' 
       AND TRIM(et.event_id) = TRIM(t1.transaction_evt_id)) 
      OR 
       ( t1.cancel_flag = 'Y' 
       AND TRIM(et.cancel_evt_id) = TRIM(t1.cancel_evt_id)) 
      ) 
     ); 
+0

상관 하위 쿼리는 일반적으로 성능에 좋지 않습니다. – DRapp

+0

정말요? [존재하지 않는 것 (NOT EXISTS)과 그렇지 않은 것 (NOT INIS)의 차이점은 무엇입니까?] (http://stackoverflow.com/questions/2246772/whats-the-difference-between-not-exists-vs-not-in) -vs-left-join-where-is-null) 또는 [상관 관계가있는 하위 쿼리에 관한 질문] (http : //asktom.oracle.com/pls/asktom/f? p = 100 : 11 : 0 :::: P11_QUESTION_ID : 3167884300346662300) 또는 [NOT INIS NOT LEIS vs. LEFT JOIN/IS NULL : Oracle] (http://explainextended.com/2009/09/17/not-in-vs-not-exists-vs-left)을 참조하십시오. -join-is-null-oracle /) – MT0

+0

Not Exists and Not In은 전체 쿼리를 사전 실행하고 모든 행을 먼저 반환 한 다음 나머지에 적용합니다. 왼쪽 조인 (LEFT JOIN)을하면 엔진이 테이블 간의 관계를 설정하기 만하면됩니다. 따라서 "ID"가 NULL인지 확인합니다. 레코드/인덱스 포인터는 주 테이블의 각 레코드가 고려되는 것과 동시에 이동합니다. 100k 취소 플래그가 있다고 가정하되 이벤트 X에만 관심이 있고 200 개의 레코드가 있으며 그 중 18 개가 취소됩니다. 200을 날려 버리면 끝난거야. – DRapp

관련 문제