테마
이 문제는 교재 18화 졸업 과제와 같은 이커머스 데이터베이스를 씁니다. 『튜너의 1년』을 순서대로 읽고 있다면 졸업 과제를 먼저 풀고 오세요. 아래 「테이블과 인덱스」 칸에 과제의 답 일부(제약 조건, 인덱스, 통계의 실제 상태)가 나옵니다.
운영팀의 「주문 관리」는 전체 주문을 최신순으로 한 쪽에 20건씩 보여 주고 위에 「총 n건」을 띄운다. 지난달까지는 목록과 건수를 두 SQL로 보냈는데, 이번 배포에서 개발자가 "DB 왕복을 한 번 줄이겠다"며 COUNT(*) OVER ()로 둘을 합쳤다.
그 뒤로 1쪽을 여는 데 걸리는 시간이 0.01초에서 0.06초로 늘고 DB 서버 CPU가 눈에 띄게 올랐다. 이 화면은 하루 약 20만 번 열린다(주문 알림을 받으면 운영자가 새로고침한다).
orders: 34,908행 · 193블록 · PK(order_id) · order_date DATE(시분초 있음) · customer_id · status · total_amountorder_id, 리프 약 70블록) · IX_ORDERS_DT (order_date, order_id)(지난달 이 화면용으로 만들었다). 주문은 날짜순으로 쌓여 있다.SELECT order_id, order_date, customer_id, status, total_amount,
COUNT(*) OVER () AS total_cnt
FROM orders
ORDER BY order_date DESC, order_id DESC
FETCH FIRST 20 ROWS ONLY
[합친 뒤 · 지금]
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:00.06 | 193 |
|* 1 | VIEW | | 1 | 34908 | 20 |00:00:00.06 | 193 |
| 2 | WINDOW SORT | | 1 | 34908 | 34908 |00:00:00.05 | 193 |
| 3 | TABLE ACCESS FULL | ORDERS | 1 | 34908 | 34908 |00:00:00.01 | 193 |
-----------------------------------------------------------------------------------------------------------
1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=20)
2번 줄 WINDOW SORT 의 Used-Mem : 2381K (0)
[합치기 전 · 지난달 · 목록]
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:00.01 | 4 |
|* 1 | VIEW | | 1 | 20 | 20 |00:00:00.01 | 4 |
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 20 | 20 |00:00:00.01 | 4 |
| 3 | TABLE ACCESS BY INDEX ROWID | ORDERS | 1 | 34908 | 20 |00:00:00.01 | 4 |
| 4 | INDEX FULL SCAN DESCENDING | IX_ORDERS_DT | 1 | 20 | 20 |00:00:00.01 | 2 |
-----------------------------------------------------------------------------------------------------------
1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=20)
2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("ORDER_DATE") DESC ,
INTERNAL_FUNCTION("ORDER_ID") DESC )<=20)
[합치기 전 · 지난달 · 건수] SELECT COUNT(*) FROM orders
SORT AGGREGATE ← INDEX FAST FULL SCAN (PK) · Buffers 75
COUNT(*) OVER ()와 부분범위 처리로 설명하시오.