Skip to content
튜닝 연습조인 튜닝
JOIN-021

탈퇴 고객 주문까지 세는 「등급별 주문 상태」 집계가 해시 조인 하나에 77MB를 쓴다

기초SELECT한빛유통171 / 700

상황 ​

경영지원팀의 「등급별 주문 상태」 리포트는 3년 치 주문을 고객 등급과 주문 상태로 묶는다. 다음 달부터 탈퇴 고객을 M_CUS에서 지우기로 해서, 개발자가 마스터에 없는 고객의 주문도 '탈퇴'로 세도록 외부 조인으로 바꿨다. 이 리포트는 매월 1일 06시 배치에서 다른 리포트 여섯 개와 함께 돈다. DBA가 V$SQL_WORKAREA에서 이 SQL의 해시 조인 하나가 77MB를 쓰는 것을 보고 물어 왔다. 개발자는 "외부 조인은 보존할 쪽(주문)부터 읽어야 해서 LEADING을 그렇게 줬다"라고 한다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · 인덱스 없음 · ORD_ST COMPLETE 90% · PENDING 8% · CANCEL 2%
  • M_CUS: 2,000행 · 30블록 · PK_M_CUS (CUS_ID) · CUS_GD A 1% · B 9% · C 90%
  • 지금은 마스터에 없는 고객의 주문이 0건이다 · 통계 최신 · pga_aggregate_target 512M · workarea_size_policy AUTO

원본 SQL ​

sql
SELECT /*+ LEADING(o c) USE_HASH(c) */
       NVL(c.CUS_GD, '탈퇴') AS cus_gd, o.ORD_ST,
       COUNT(*) AS ord_cnt, SUM(o.ORD_AMT) AS ord_amt
  FROM T_ORD_BIG o, M_CUS c
 WHERE c.CUS_ID(+) = o.CUS_ID
 GROUP BY NVL(c.CUS_GD, '탈퇴'), o.ORD_ST

실행계획 학습용 예시 · 교재 06화 규모 ​

xplan
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |           |      1 |        |      9 |00:00:00.62 |    5856 |       |       |          |
|   1 |  HASH GROUP BY      |           |      1 |      9 |      9 |00:00:00.62 |    5856 |  1116K|  1116K|  764K (0)|
|*  2 |   HASH JOIN OUTER   |           |      1 |   1000K|   1000K|00:00:00.44 |    5856 |    61M|  8436K|   77M (0)|
|   3 |    TABLE ACCESS FULL| T_ORD_BIG |      1 |   1000K|   1000K|00:00:00.05 |    5826 |       |       |          |
|   4 |    TABLE ACCESS FULL| M_CUS     |      1 |   2000 |   2000 |00:00:00.01 |      30 |       |       |          |
--------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("C"."CUS_ID"(+)="O"."CUS_ID")

문제 ​

  1. 2번 줄의 해시 조인에서 어느 쪽이 build인지 찾고, Buffers는 두 테이블을 한 번씩 읽은 만큼인데 메모리가 77MB나 드는 이유를 설명하시오.
  2. 외부 조인의 결과('탈퇴' 포함)는 그대로 두고 M_CUS가 build가 되도록 SQL을 고치시오. "외부 조인은 보존할 쪽부터 읽어야 한다"는 말이 해시 조인에서도 맞는지 서술하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자