Skip to content
튜닝 연습파싱과 바인드 변수
PARSE-026

리뷰 검수 화면이 하루에 서너 번, 한 번씩만 튄다

중급SELECT이커머스571 / 700

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

상황 ​

이커머스 관리자 「리뷰 검수」 화면은 운영자가 대개 오늘 들어온 리뷰를 보고, 품질팀은 1년치를 내려 본다. 하루 4,000번쯤 호출된다. DBA가 보낸 표에는 이 문장이 하루 서너 번 3,000블록 넘게 읽는 실행이 있고, 바로 다음부터는 1년을 넘겨도 775블록으로 내려간다. 공유 풀이 빠듯해서 이 문장은 하루에도 몇 번씩 밀려났다가 다시 올라온다(LOADS 4). 개발 리더가 물었다. "오라클이 알아서 고친다면 그냥 둬도 되는 것 아닌가요?"

테이블과 인덱스 ​

  • reviews: 15,000행 · 775블록 · created_at DATE(시분초 있음, 2020 ~ 2024 · 하루 약 8건) · 행은 created_at 순서와 상관없이 흩어져 있다 · content CLOB은 이 화면에서 읽지 않는다
  • 인덱스: PK(review_id) · IX_REV_CREATED (created_at)(이 문제용 · 높이 2 · 리프 약 40블록)
  • 통계 최신 · 히스토그램 없음 · statistics_level = TYPICAL · 바인드 피킹 켬

원본 SQL ​

sql
SELECT review_id, product_id, customer_id, rating, created_at
  FROM reviews
 WHERE created_at >= :d1
   AND created_at <  :d2
 ORDER BY created_at DESC

실행계획 학습용 예시 ​

xplan
[V$SQL — 16:20 · 13:05에 다시 올라온 커서]
 CHILD  EXEC  BUFFER_GETS  IS_BIND_SENSITIVE  IS_BIND_AWARE  IS_SHAREABLE  PLAN_HASH
     0     2        3,014  Y                  N              N             1503917384
     1     6        4,668  Y                  Y              Y             2865032113
     2   611        6,110  Y                  Y              Y             1503917384

[V$SQL_CS_HISTOGRAM]  자식 0 → 0:1 1:1 2:0 · 자식 1 → 0:6 · 자식 2 → 0:611
[V$SQL_SHARED_CURSOR] 자식 1 · 2 : BIND_EQUIV_FAILURE = Y
[V$SQL_CS_SELECTIVITY]
 CHILD  PREDICATE  RANGE_ID  LOW       HIGH
     1  >=D1              0  0.180108  0.220132
     1  <D2               0  0.899955  1.099945
     2  >=D1              0  0.000495  0.000605
     2  <D2               0  0.899955  1.099945

[자식 0 · 13:41 · 1년 조회 한 번 (자식 0은 13:05에 오늘 하루로 태어났다)]
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                |      1 |        |   3001 |00:00:00.04 |    3004 |          |
|*  1 |  FILTER                        |                |      1 |        |   3001 |00:00:00.04 |    3004 |          |
|   2 |   TABLE ACCESS BY INDEX ROWID  | REVIEWS        |      1 |      8 |   3001 |00:00:00.04 |    3004 |          |
|*  3 |    INDEX RANGE SCAN DESCENDING | IX_REV_CREATED |      1 |      8 |   3001 |00:00:00.01 |      10 |          |
-------------------------------------------------------------------------------------------------------------------
   1 - filter(:D1<:D2)
   3 - access("CREATED_AT"<:D2 AND "CREATED_AT">=:D1)

[자식 1 · 1년 · 'ALLSTATS LAST']
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                |      1 |        |   3001 |00:00:00.01 |     775 |          |
|   1 |  SORT ORDER BY                 |                |      1 |   3003 |   3001 |00:00:00.01 |     775 |  267K (0)|
|*  2 |   FILTER                       |                |      1 |        |   3001 |00:00:00.01 |     775 |          |
|*  3 |    TABLE ACCESS FULL           | REVIEWS        |      1 |   3003 |   3001 |00:00:00.01 |     775 |          |
-------------------------------------------------------------------------------------------------------------------
   2 - filter(:D1<:D2)
   3 - filter(("CREATED_AT">=:D1 AND "CREATED_AT"<:D2))

문제 ​

  1. 13:05 이후 이 문장에 일어난 일을 순서대로 설명하시오. 왜 하루에 서너 번 같은 일이 되풀이되는지도 쓰시오.
  2. 개발 리더의 말처럼 그냥 둬도 되는지 판단하고, 나쁜 실행 한 번까지 없애도록 SQL을 고치시오. 고친 방법의 대가도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자