테마
이 문제는 교재 18화 졸업 과제와 같은 이커머스 데이터베이스를 씁니다. 『튜너의 1년』을 순서대로 읽고 있다면 졸업 과제를 먼저 풀고 오세요. 아래 「테이블과 인덱스」 칸에 과제의 답 일부(제약 조건, 인덱스, 통계의 실제 상태)가 나옵니다.
이커머스 메인 화면에는 최근 30일 동안 많이 본 상품 10개가 뜬다. API 서버는 최근 30일의 조회 기록을 모두 받아 와 상품별로 세고, 상위 10개를 골라 상품명을 하나씩 읽는다. 메인 화면은 초당 20번쯤 열린다. 메인 화면 응답 0.21초 가운데 이 칸이 0.11초다. 개발자는 "조회 기록이 1,600건 남짓이라 자바에서 세는 게 DB를 덜 괴롭힌다"라고 한다.
product_views: 100,000행 · 367블록 · view_id · product_id · customer_id · view_date · 인덱스는 PK뿐 · 최근 30일 조회 약 1,640건products: 280행 · 8블록 · PK (product_id) · 상품명은 name// PopularApi.java : 30일 치 조회 기록을 다 받아 와 자바에서 센다
List<Long> views = jdbc.queryForList(
"SELECT product_id FROM product_views WHERE view_date >= SYSDATE - 30", Long.class);
Map<Long, Integer> cnt = new HashMap<>();
for (Long p : views) cnt.merge(p, 1, Integer::sum);
List<Long> top10 = cnt.entrySet().stream()
.sorted(Map.Entry.<Long, Integer>comparingByValue().reversed())
.limit(10).map(Map.Entry::getKey).collect(toList());
for (Long p : top10) {
names.add(jdbc.queryForObject("SELECT name FROM products WHERE product_id = ?", String.class, p));
}
[메인 화면 한 번 · 세션 통계 증가분]
execute count 11
SQL*Net roundtrips to/from client 176
session logical reads 553
bytes sent via SQL*Net to client 19 KB
SQL*Net message from client 176번 · 0.09 초
[V$SQL · 조회 기록 문장] EXECUTIONS 1 · FETCHES 165 · ROWS_PROCESSED 1,642 · BUFFER_GETS 532
---------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1642 |00:00:00.01 | 532 |
|* 1 | TABLE ACCESS FULL| PRODUCT_VIEWS | 1 | 1644 | 1642 |00:00:00.01 | 532 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("VIEW_DATE">=SYSDATE@!-30)
[상품명 문장] SELECT name FROM products WHERE product_id = :1 · 화면 한 번에 10번 · 한 번 2블록