Skip to content
튜닝 연습서브쿼리와 쿼리 변환
SUBQ-006

취소 주문은 549건뿐인데 6월 주문 내려받기가 취소 테이블을 2만 7천 번 찾아간다

기초SELECT한빛유통241 / 700

상황 ​

정산팀은 매달 초 지난달 주문 전체를 내려받아 회계 시스템과 대사한다. 파일에는 취소 주문의 취소 사유 칸이 있다. 6월 치 27,390건을 한 번 내려받을 때 6만 블록을 읽고, 담당자 다섯 명이 월초 사흘 동안 수십 번씩 내려받아 그 기간에는 이 SQL이 논리 읽기 상위에 오른다. SQL을 짠 조민우는 "취소 사유는 스칼라 서브쿼리로 붙였다. 취소가 아닌 주문은 사유가 없어 NULL이 나오고, 캐시도 있으니 문제없다"라고 했다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · 인덱스 없음 · 2024년 6월 27,390건 · ORD_ST CANCEL 2%(6월은 549건) · ORD_SEQ는 주문마다 다르다
  • T_ORD_CNCL 주문취소(이 문제에서 쓰는 파생 테이블): T_ORD_BIG의 취소 주문 20,000건 · 2,860블록 · PK_T_ORD_CNCL (ORD_SEQ)(높이 2) · CNCL_DT · CNCL_RSN(사유 문구) · CNCL_MEMO(상담원 메모, 평균 900바이트라 행이 길다)
  • 업무 규칙은 "취소를 철회하면 T_ORD_CNCL의 행을 지우고 주문 상태를 되돌린다"이다 · FK도 제약도 없다 · 통계 최신

원본 SQL ​

sql
SELECT o.ORD_SEQ, o.CUS_ID, o.ORD_DT, o.ORD_ST, o.ORD_AMT,
       (SELECT c.CNCL_RSN
          FROM T_ORD_CNCL c
         WHERE c.ORD_SEQ = o.ORD_SEQ) AS cncl_rsn
  FROM T_ORD_BIG o
 WHERE o.ORD_DT >= DATE '2024-06-01'
   AND o.ORD_DT <  DATE '2024-07-01'
 ORDER BY o.ORD_SEQ

실행계획 학습용 예시 ​

xplan
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |      1 |        |  27390 |00:00:00.31 |   61155 |          |
|   1 |  TABLE ACCESS BY INDEX ROWID| T_ORD_CNCL    |  27390 |      1 |    549 |00:00:00.17 |   55329 |          |
|*  2 |   INDEX UNIQUE SCAN         | PK_T_ORD_CNCL |  27390 |      1 |    549 |00:00:00.08 |   54780 |          |
|   3 |  SORT ORDER BY              |               |      1 |  27390 |  27390 |00:00:00.31 |   61155 | 1726K (0)|
|*  4 |   TABLE ACCESS FULL         | T_ORD_BIG     |      1 |  27390 |  27390 |00:00:00.05 |    5826 |          |
-------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("C"."ORD_SEQ"=:B1)
   4 - filter(("O"."ORD_DT">=TO_DATE(' 2024-06-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "O"."ORD_DT"<TO_DATE(' 2024-07-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))

문제 ​

  1. 1번과 2번 줄의 Starts가 27,390인데 A-Rows는 549인 이유를 설명하시오. 스칼라 서브쿼리 캐시가 이 일을 줄여 주지 못한 이유도 쓰시오.
  2. 결과가 바뀌지 않게 SQL을 고치시오. 결과가 같으려면 데이터에서 무엇을 확인해야 하는지 쓰고, 외부 조인으로 바꾸는 방법과 일량을 비교하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자