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

상담원이 리뷰에서 「환불」을 찾을 때마다 리뷰 1만 5천 건을 다 읽는다

실전SELECT이커머스46 / 700

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

상황 ​

이커머스 고객센터와 MD팀은 「리뷰 키워드 검색」 화면으로 불만 리뷰를 찾는다(전체 리뷰 검색, 하루 약 400번). 고객용 상품 상세 페이지의 「리뷰 내 검색」도 같은 모양의 SQL에 상품 번호를 더해 쓴다(하루 약 3만 번). 개발자는 "LIKE 앞뒤에 %가 있어서 어떤 인덱스로도 안 된다. 검색 엔진을 들이든지 리뷰 검색을 빼자"고 한다. 박팀장은 두 화면을 나눠 각각 무엇으로 받칠지 대가까지 정리해 오라고 했다.

테이블과 인덱스 ​

  • reviews: 15,000행 · 775블록 · PK만 있다 · product_id(상품 280개, 상품당 34 ~ 76건) · customer_id · rating 1 ~ 5 · content CLOB(평균 약 600바이트, 행 안에 저장) · created_at DATE
  • 리뷰는 하루 약 40건씩 는다. 상담원 화면은 전날까지 쓴 리뷰가 검색되면 된다(현업 확인)
  • 통계 최신

원본 SQL ​

sql
-- S1 고객센터 · MD 「리뷰 키워드 검색」 (전체)
SELECT review_id, product_id, rating, created_at
  FROM reviews
 WHERE content LIKE '%' || :v_kw || '%'
 ORDER BY created_at DESC;

-- S2 상품 상세 「리뷰 내 검색」
SELECT review_id, rating, created_at
  FROM reviews
 WHERE product_id = :v_prod
   AND content LIKE '%' || :v_kw || '%'
 ORDER BY created_at DESC;

실행계획 학습용 예시 ​

xplan
[S1 · '환불']
----------------------------------------------------------------------------------------
| Id  | Operation          | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |      1 |        |    212 |00:00:00.19 |     775 |
|   1 |  SORT ORDER BY     |         |      1 |    750 |    212 |00:00:00.19 |     775 |
|*  2 |   TABLE ACCESS FULL| REVIEWS |      1 |    750 |    212 |00:00:00.19 |     775 |
----------------------------------------------------------------------------------------
   2 - filter("CONTENT" LIKE '%'||:V_KW||'%')

[S2 · 상품 117 · '사이즈']
----------------------------------------------------------------------------------------
| Id  | Operation          | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |      1 |        |      6 |00:00:00.17 |     775 |
|   1 |  SORT ORDER BY     |         |      1 |      3 |      6 |00:00:00.17 |     775 |
|*  2 |   TABLE ACCESS FULL| REVIEWS |      1 |      3 |      6 |00:00:00.17 |     775 |
----------------------------------------------------------------------------------------
   2 - filter(("PRODUCT_ID"=:V_PROD AND "CONTENT" LIKE '%'||:V_KW||'%'))

문제 ​

  1. S1과 S2가 똑같이 FULL이지만 고칠 길이 다른 이유를 설명하시오.
  2. S2를 B-tree 인덱스로 받치는 DDL을 작성하시오.
  3. S1을 받칠 방법(Oracle Text 인덱스와 CONTAINS, 외부 검색 엔진, 요구 조정)을 비교하고, 고른 방법의 SQL과 대가를 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자