테마
버거원이 가맹점 포털을 연다. 오픈 전 점검에서 SQL 넷이 걸렸다. 넷 다 운영 주문 ORD_RANDOM을 읽는데, 쓸 수 있는 인덱스가 날짜 인덱스 X01 하나뿐이다. 점주 앱(P1 ~ P3)은 매장 200곳이 수시로 열고, 본사 순위 화면(P4)은 10분마다 새로 고친다.
박팀장은 이렇게 주문했다. "인덱스는 최소로. 넷이 각각 무엇을 읽는지, 하루 일량으로 보면 무엇이 급한지, 만들면 POS 적재에 무엇이 붙는지까지 적어 와라."
ORD_RANDOM(운영본): 1,000,000행 · 22,414블록(블록당 약 45행) · 서버 교체 때 무작위 순서로 다시 적재했다 · 하루 약 1,370건 · 매장 200곳(매장 하나의 하루 주문은 평균 6.9건, 한 달 약 208건) · POS가 판매마다 INSERT하고, 매월 초 정정분 약 4만 건을 다시 넣는다ORD_DT VARCHAR2(8) · ORD_HMS VARCHAR2(6) · SHOP_NO VARCHAR2(10) 'SH0001' · ORD_NO NUMBER(10)ORD_RANDOM_PK (ORD_NO) · ORD_RANDOM_X01 (ORD_DT, ORD_HMS): BLEVEL 2 · 리프 3,774블록 · CLUSTERING_FACTOR 999,958(교재 04화 실측) · 「일별 주문 조회」(ORD_DT = :d ORDER BY ORD_HMS, 첫 화면 30줄)도 X01을 쓴다SHOP_NO 6바이트, ORD_DT 8바이트, ORD_HMS 6바이트-- P1 「시간대별 주문 수」 · 점주 앱 · 하루 약 8,000번
SELECT SUBSTR(ORD_HMS, 1, 2) AS hh, COUNT(*) AS cnt
FROM ORD_RANDOM
WHERE SHOP_NO = :v_shop AND ORD_DT = :v_dt
GROUP BY SUBSTR(ORD_HMS, 1, 2);
-- P2 「매장 주문 목록」 · 점주 앱 · 하루 약 4,000번
SELECT ORD_NO, ORD_HMS
FROM ORD_RANDOM
WHERE SHOP_NO = :v_shop AND ORD_DT = :v_dt
ORDER BY ORD_HMS;
-- P3 「월 주문 추이」 · 점주 앱 · 하루 약 2,000번 · 한 달
SELECT ORD_DT, COUNT(*) AS cnt
FROM ORD_RANDOM
WHERE SHOP_NO = :v_shop AND ORD_DT BETWEEN :v_from AND :v_to
GROUP BY ORD_DT;
-- P4 「오늘 매장 순위」 · 본사 · 하루 약 150번
SELECT SHOP_NO, COUNT(*) AS cnt
FROM ORD_RANDOM
WHERE ORD_DT = :v_dt
GROUP BY SHOP_NO;
[P3 · SH0042 · 2013년 11월]
--------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 30 |00:00:00.06 | 41838 |
| 1 | HASH GROUP BY | | 1 | 20 | 30 |00:00:00.06 | 41838 |
|* 2 | FILTER | | 1 | | 208 |00:00:00.06 | 41838 |
|* 3 | TABLE ACCESS BY INDEX ROWID BATCHED| ORD_RANDOM | 1 | 20 | 208 |00:00:00.06 | 41838 |
|* 4 | INDEX RANGE SCAN | ORD_RANDOM_X01 | 1 | 4065 | 41666 |00:00:00.01 | 160 |
--------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:V_FROM<=:V_TO)
3 - filter("SHOP_NO"=:V_SHOP)
4 - access("ORD_DT">=:V_FROM AND "ORD_DT"<=:V_TO)
[P1 · SH0042 · 2013-11-15]
--------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 6 |00:00:00.01 | 1378 |
| 1 | HASH GROUP BY | | 1 | 7 | 6 |00:00:00.01 | 1378 |
|* 2 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD_RANDOM | 1 | 7 | 7 |00:00:00.01 | 1378 |
|* 3 | INDEX RANGE SCAN | ORD_RANDOM_X01 | 1 | 1370 | 1371 |00:00:00.01 | 8 |
--------------------------------------------------------------------------------------------------------------------
2 - filter("SHOP_NO"=:V_SHOP)
3 - access("ORD_DT"=:V_DT)
[P2 · P4] P1과 같은 모양 · Buffers 약 1,378 (P2는 SORT ORDER BY가 붙는다)