Skip to content
튜닝 연습서브쿼리와 쿼리 변환
SUBQ-012

상품 280개짜리 평점 요약표가 리뷰 테이블을 560번 읽는다

중급SELECT이커머스247 / 700

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

상황 ​

MD팀의 「카테고리별 평점 현황」은 카테고리마다 상품 수, 리뷰 수, 상품 평점의 평균을 보여 준다. 기획 회의 때마다 여러 번 돌리는데 한 번에 1.1초 걸린다. 개발자는 "19c부터는 옵티마이저가 스칼라 서브쿼리를 알아서 조인으로 펼친다고 들었는데, 계획에는 서브쿼리가 그대로 남아 있다"라고 했다.

테이블과 인덱스 ​

  • products: 280행 · 8블록 · PK만 있음 · 상품이 달린 카테고리는 40개
  • reviews: 15,000행 · 775블록 · PK(review_id)만 있음 · 상품당 34 ~ 76건 · product_id에는 인덱스가 없다
  • 스칼라 서브쿼리 Unnesting은 켜져 있다(기본값) · 통계 최신

원본 SQL ​

sql
SELECT p.category_id,
       COUNT(*) AS product_cnt,
       SUM((SELECT COUNT(*) FROM reviews r WHERE r.product_id = p.product_id)) AS review_cnt,
       ROUND(AVG((SELECT AVG(r.rating) FROM reviews r WHERE r.product_id = p.product_id)), 2) AS avg_rating
  FROM products p
 GROUP BY p.category_id
 ORDER BY p.category_id

실행계획 학습용 예시 ​

xplan
--------------------------------------------------------------------------------------------
| Id  | Operation          | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |          |      1 |        |     40 |00:00:01.12 |     434K|
|   1 |  SORT AGGREGATE    |          |    280 |      1 |    280 |00:00:00.55 |     217K|
|*  2 |   TABLE ACCESS FULL| REVIEWS  |    280 |     54 |  15000 |00:00:00.54 |     217K|
|   3 |  SORT AGGREGATE    |          |    280 |      1 |    280 |00:00:00.56 |     217K|
|*  4 |   TABLE ACCESS FULL| REVIEWS  |    280 |     54 |  15000 |00:00:00.55 |     217K|
|   5 |  SORT GROUP BY     |          |      1 |     40 |     40 |00:00:01.12 |     434K|
|   6 |   TABLE ACCESS FULL| PRODUCTS |      1 |    280 |    280 |00:00:00.01 |       8 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("R"."PRODUCT_ID"=:B1)
   4 - filter("R"."PRODUCT_ID"=:B1)

(DBMS_XPLAN 이 줄여 쓴 값 — 217K = 217,000 · 434K = 434,008)

문제 ​

  1. 1번과 3번 줄의 Starts와 Buffers로 리뷰 테이블을 몇 번, 몇 블록 읽었는지 계산하시오. Unnesting이 켜져 있는데도 스칼라 서브쿼리가 펼쳐지지 않은 이유를 설명하시오.
  2. 결과가 바뀌지 않게 SQL을 고치시오. 리뷰가 없는 상품이 생겨도 원래와 같은 답이 나오도록 하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자