테마
이 문제는 교재 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은 이 화면에서 읽지 않는다review_id) · IX_REV_CREATED (created_at)(이 문제용 · 높이 2 · 리프 약 40블록)statistics_level = TYPICAL · 바인드 피킹 켬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
[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))