테마
정산팀은 매달 초 지난달 결제 완료 주문 가운데 검수할 주문을 뽑는다. 검수 대상은 (가) 단가 50만 원 이상 상품이 들어 있는 주문이거나 (나) 정산 금액이 결제 금액과 다르게 적재된 주문이다. 조회는 9초가 걸리고, 정산팀은 화면이 멈춘 줄 알고 몇 번씩 다시 누른다. 조민우는 OR를 UNION ALL로 나눠 보겠다며 고친 SQL을 시험해 봤는데, 결과가 302건이 아니라 305건이 나왔다. 박팀장은 고친 SQL과 함께, 인덱스로 해결하자는 DBA 의견도 비교해 달라고 했다.
T_ORD 주문: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ) · 2024년 7월 결제 완료 주문 3,812건T_ORD_DET 주문상세: 200,000행 · 896블록 · PK_T_ORD_DET (ORD_SEQ, ORD_DET_NO) · 주문당 1 ~ 3건 · 단가 50만 원 이상인 줄 9,960개T_ORD_STLM 정산: 100,000행 · 640블록 · 인덱스 없음 · 정산 배치가 밤마다 T_ORD에서 적재한다 · STLM_AMT NOT NULLSELECT o.ORD_SEQ, o.CUS_ID, o.PAY_DT, o.PAY_AMT
FROM T_ORD o
WHERE o.PAY_DT >= :d1 AND o.PAY_DT < :d2
AND o.ORD_ST = 'COMPLETE'
AND (EXISTS (SELECT 1
FROM T_ORD_DET d
WHERE d.ORD_SEQ = o.ORD_SEQ
AND d.UNT_PRC >= :v_prc) -- (가) 고가 상품
OR EXISTS (SELECT 1
FROM T_ORD_STLM s
WHERE s.ORD_SEQ = o.ORD_SEQ
AND s.STLM_AMT <> o.PAY_AMT)) -- (나) 정산 금액 불일치
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 302 | 00:00:09.12 | 2276K |
|* 1 | FILTER | | 1 | | 302 | 00:00:09.12 | 2276K |
|* 2 | TABLE ACCESS FULL | T_ORD | 1 | 3790 | 3812 | 00:00:00.01 | 896 |
|* 3 | TABLE ACCESS BY INDEX ROWID BATCHED | T_ORD_DET | 3812 | 1 | 274 | 00:00:00.03 | 11436 |
|* 4 | INDEX RANGE SCAN | PK_T_ORD_DET | 3812 | 2 | 7240 | 00:00:00.01 | 7624 |
|* 5 | TABLE ACCESS FULL | T_ORD_STLM | 3538 | 1 | 31 | 00:00:09.05 | 2264K |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(( EXISTS (SELECT 0 FROM "T_ORD_DET" "D" WHERE "D"."ORD_SEQ"=:B1 AND "D"."UNT_PRC">=:V_PRC) OR
EXISTS (SELECT 0 FROM "T_ORD_STLM" "S" WHERE "S"."ORD_SEQ"=:B2 AND "S"."STLM_AMT"<>:B3)))
2 - filter(("O"."ORD_ST"='COMPLETE' AND "O"."PAY_DT">=:D1 AND "O"."PAY_DT"<:D2))
3 - filter("D"."UNT_PRC">=:V_PRC)
4 - access("D"."ORD_SEQ"=:B1)
5 - filter(("S"."ORD_SEQ"=:B1 AND "S"."STLM_AMT"<>:B2))
LNNVL을 쓸 수 없는 이유를 설명하시오.T_ORD_STLM에 (ORD_SEQ) 인덱스를 만들고 SQL은 그대로 두는 안, 두 서브쿼리를 하나의 조인으로 합치는 안과 비교해 일량과 부작용을 서술하시오.