Skip to content
튜닝 연습인덱스 사용 조건
IDX-044

「비회원 유입」 차트 하나가 1분마다 상품 조회 로그 10만 건을 다 읽는다

중급SELECT이커머스44 / 700

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

상황 ​

마케팅팀 대시보드의 「비회원 유입」 차트는 최근 30일 동안 로그인하지 않은 방문자의 상품 조회 수를 날짜별로 그린다. 마케터 열 명의 화면이 1분마다 새로 고친다. 개발자는 회원별 「최근 본 상품」 화면용으로 만든 customer_id 인덱스를 이 차트에도 쓰려고 INDEX 힌트를 붙였지만 계획은 FULL 그대로다. 개발자는 "IS NULL은 인덱스를 못 타니 비회원을 'GUEST' 같은 값으로 채우자"고 제안했다.

테이블과 인덱스 ​

  • product_views 상품 조회 로그: 100,000행 · 367블록 · view_id(PK) · product_id · customer_id(비회원 조회는 NULL) · view_date DATE(시분초 있음, NOT NULL)
  • 최근 1년치만 남긴다 · 하루 약 274건 · 비회원 조회 약 31%(30일에 약 2,550건) (문제 설정: 보관 기간과 비회원 비율은 이 문제에서 정한 값이다)
  • 인덱스: PK와 IX_PV_CUST (customer_id)(회원 화면용 · 리프 약 160블록) · 통계 최신
  • 회원 화면 SQL: WHERE customer_id = :c ORDER BY view_date DESC FETCH FIRST 20 ROWS ONLY(하루 수만 번)

원본 SQL ​

sql
SELECT /*+ INDEX(v IX_PV_CUST) */ TRUNC(view_date) AS view_day, COUNT(*) AS guest_views
  FROM product_views v
 WHERE customer_id IS NULL
   AND view_date >= TRUNC(:v_to) - 29
   AND view_date <  TRUNC(:v_to) + 1
 GROUP BY TRUNC(view_date)
 ORDER BY view_day

실행계획 학습용 예시 ​

xplan
-----------------------------------------------------------------------------------------------
| Id  | Operation           | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |               |      1 |        |     30 |00:00:00.02 |     367 |
|   1 |  SORT GROUP BY      |               |      1 |     30 |     30 |00:00:00.02 |     367 |
|*  2 |   FILTER            |               |      1 |        |   2548 |00:00:00.02 |     367 |
|*  3 |    TABLE ACCESS FULL| PRODUCT_VIEWS |      1 |   2534 |   2548 |00:00:00.02 |     367 |
-----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TRUNC(:V_TO)-29<TRUNC(:V_TO)+1)
   3 - filter(("CUSTOMER_ID" IS NULL AND "VIEW_DATE">=TRUNC(:V_TO)-29 AND "VIEW_DATE"<TRUNC(:V_TO)+1))

Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1 (U - Unused (1))
   3 -  SEL$1 / "V"@"SEL$1"
         U -  INDEX(v IX_PV_CUST)

문제 ​

  1. INDEX 힌트가 쓰이지 않은 이유를 IX_PV_CUST에 무엇이 들어 있는지로 설명하시오.
  2. 비회원을 다른 값으로 채우지 않고, 인덱스 하나를 바꿔 회원 화면과 이 차트를 둘 다 범위로 읽게 하시오.
  3. 바꾼 인덱스에서 customer_id IS NULL이 어떻게 access 조건이 되는지 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자