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

고객센터 '이메일로 주문 찾기'가 결과 두 줄에 600블록을 읽는다

기초SELECT이커머스160 / 700

이 문제는 교재 18화 졸업 과제와 같은 이커머스 데이터베이스를 씁니다. 『튜너의 1년』을 순서대로 읽고 있다면 졸업 과제를 먼저 풀고 오세요. 아래 「테이블과 인덱스」 칸에 과제의 답 일부(제약 조건, 인덱스, 통계의 실제 상태)가 나옵니다.

상황 ​

고객센터 상담원은 고객이 불러 주는 이메일로 최근 30일 주문을 찾는다. 상담원 40명이 하루 1만 번쯤 누른다. 18화 T2 절차로 orders에 인덱스 두 개가 생긴 뒤에도 이 화면만은 그대로라는 민원이 올라왔다. 개발자는 "주문 화면이니 주문부터 읽게 힌트를 달았다"라고 한다. 아래는 고객 한 명(최근 30일 주문 2건)을 조회한 실행계획이다.

테이블과 인덱스 ​

  • customers: 5,230행 · 51블록 · PK_CUSTOMERS (customer_id) · UQ_CUSTOMERS_EMAIL (email)
  • orders: 34,908행 · 193블록 · PK_ORDERS (order_id) · IX_ORDERS_DT (order_date) · IX_ORDERS_CUST_DT (customer_id, order_date) (둘 다 18화 T2로 승인된 인덱스)
  • 주문은 하루 평균 19건 · 2024-12-02 ~ 12-31의 30일은 573건 · 통계 최신

원본 SQL ​

sql
SELECT /*+ LEADING(o c) USE_NL(c) */
       o.order_id, o.order_date, o.status, o.total_amount
  FROM orders o, customers c
 WHERE c.email       = :email
   AND o.customer_id = c.customer_id
   AND o.order_date >= :d_from
 ORDER BY o.order_date DESC

실행계획 학습용 예시 ​

xplan
------------------------------------------------------------------------------------------------------------------
| Id  | Operation                               | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                        |              |      1 |        |      2 |00:00:00.01 |     611 |
|   1 |  SORT ORDER BY                          |              |      1 |      1 |      2 |00:00:00.01 |     611 |
|   2 |   NESTED LOOPS                          |              |      1 |      1 |      2 |00:00:00.01 |     611 |
|   3 |    NESTED LOOPS                         |              |      1 |    573 |    573 |00:00:00.01 |      38 |
|   4 |     TABLE ACCESS BY INDEX ROWID BATCHED | ORDERS       |      1 |    573 |    573 |00:00:00.01 |      10 |
|*  5 |      INDEX RANGE SCAN                   | IX_ORDERS_DT |      1 |    573 |    573 |00:00:00.01 |       3 |
|*  6 |     INDEX UNIQUE SCAN                   | PK_CUSTOMERS |    573 |      1 |    573 |00:00:00.01 |      28 |
|*  7 |    TABLE ACCESS BY INDEX ROWID          | CUSTOMERS    |    573 |      1 |      2 |00:00:00.01 |     573 |
------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   5 - access("O"."ORDER_DATE">=:D_FROM)
   6 - access("C"."CUSTOMER_ID"="O"."CUSTOMER_ID")
   7 - filter("C"."EMAIL"=:EMAIL)

문제 ​

  1. 7번 줄의 Starts와 A-Rows를 비교해 이 조인이 무엇을 낭비하는지 설명하시오.
  2. 두 조건(이메일, 최근 30일)이 각각 몇 행을 남기는지 비교해 드라이빙 테이블을 정하고 개선 SQL을 작성하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자