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

메뉴별 월 판매 수량에 매장도 메뉴 이름도 안 쓰는데 주문 100만 건을 맞대 본다

중급SELECT버거214 / 700

상황 ​

본사 영업팀은 BI 도구로 「메뉴별 월 판매 수량」을 매일 아침 뽑는다. BI 도구는 사내 표준 뷰 V_ORD_ITEM_DTL만 볼 수 있게 되어 있고, 이 리포트에 나오는 칸은 메뉴 번호, 수량, 줄 수뿐이다. DBA는 "FK가 있으니 주문 조인은 옵티마이저가 알아서 지울 것"이라고 했지만, 실행계획에는 주문과 상품이 그대로 남아 있다. 이 FK는 2014년 신 POS로 옮길 때 검증 시간을 줄이려고 ENABLE NOVALIDATE로 켰다. 아래는 2013년 12월로 조회한 실행계획이다.

테이블과 인덱스 ​

  • 뷰 V_ORD_ITEM_DTL: ORD_ITEM i JOIN ORD o ON o.ORD_NO = i.ORD_NO JOIN ITEM t ON t.ITEM_ID = i.ITEM_ID · i의 컬럼 전부와 o.SHOP_NO, t.ITEM_NM, t.ITEM_TYPE_CD를 내보낸다 · ORD_DT는 i.ORD_DT를 내보낸다
  • ORD_ITEM: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS) · 12월 104,750줄(X01 리프 약 390블록, 테이블 약 2,340블록) · ITEM_ID는 NOT NULL
  • ORD: 1,000,000행 · 22,422블록 · ORD_PK (ORD_NO)(리프 약 2,200블록) / ITEM: 92행 · 5블록 · ITEM_PK (ITEM_ID)
  • 제약: FK_ORD_ITEM_ORD (ORD_ITEM.ORD_NO → ORD) ENABLE NOVALIDATE · ORD_ITEM.ITEM_ID → ITEM FK는 없다
  • 어제 점검에서 주문이 없는 주문상품, 상품 마스터에 없는 메뉴 번호는 모두 0건이었다 · 통계 최신

원본 SQL ​

sql
SELECT ITEM_ID, SUM(ORD_ITEM_QTY) AS qty, COUNT(*) AS lines
  FROM V_ORD_ITEM_DTL
 WHERE ORD_DT BETWEEN :v_from AND :v_to
 GROUP BY ITEM_ID
 ORDER BY ITEM_ID

실행계획 학습용 예시 ​

xplan
-------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                         |              |      1 |        |     92 |00:00:00.62 |    4977 |           |
|   1 |  SORT GROUP BY                           |              |      1 |     92 |     92 |00:00:00.62 |    4977 |  6144 (0) |
|*  2 |   HASH JOIN                              |              |      1 |   104K |   104K |00:00:00.58 |    4977 | 1345K (0) |
|   3 |    INDEX FULL SCAN                       | ITEM_PK      |      1 |     92 |     92 |00:00:00.01 |       1 |           |
|*  4 |    HASH JOIN                             |              |      1 |   104K |   104K |00:00:00.55 |    4976 | 6123K (0) |
|   5 |     TABLE ACCESS BY INDEX ROWID BATCHED  | ORD_ITEM     |      1 |   104K |   104K |00:00:00.04 |    2729 |           |
|*  6 |      INDEX RANGE SCAN                    | ORD_ITEM_X01 |      1 |   104K |   104K |00:00:00.01 |     392 |           |
|   7 |     INDEX FAST FULL SCAN                 | ORD_PK       |      1 |  1000K |  1000K |00:00:00.12 |    2247 |           |
-------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("T"."ITEM_ID"="I"."ITEM_ID")
   4 - access("O"."ORD_NO"="I"."ORD_NO")
   6 - access("I"."ORD_DT">=:V_FROM AND "I"."ORD_DT"<=:V_TO)

문제 ​

  1. FK가 있는데도 4번 줄의 주문 조인이 지워지지 않은 이유와, 2번 줄의 상품 조인이 남은 이유를 각각 설명하시오. 두 조인이 이 SQL에 더하는 일량을 줄 번호와 숫자로 쓰시오.
  2. 화면 SQL과 뷰를 고치지 않고 두 조인이 계획에서 사라지게 하는 DDL을 작성하시오. 실행하기 전에 확인할 것과, 운영 중에 실행할 때 주의할 점을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자