테마
본사 「매장별 일 주문 현황」 화면(주문 건수, 첫 주문과 마지막 주문 시각)은 점장과 본사 직원이 전날 하루를 넘겨 연다(하루 약 2,000번). 같은 DAO 메서드를 월 정산 리포트도 쓰는데, 리포트는 한 달을 넘긴다. 리포트는 낮에 본사 직원이 열기도 하고 밤에 예약 실행되기도 한다(합쳐서 하루 30번쯤). 분석용 사본은 매일 01:00에 새로 적재하고 바로 통계를 기본값으로 모은다. 오과장이 말했다. "어떤 날은 괜찮고 어떤 날은 느린데, 그날그날 달라요. 배포도 없었고 SQL도 그대로예요."
ORD_RANDOM: 1,000,000행 · 22,414블록 · POS 원장 ORD를 무작위 순서로 복제한 본사 분석용 사본 · ORD_DT VARCHAR2(8) · 하루 약 1,370건 · 매장 200곳ORD_RANDOM_X01 (ORD_DT, ORD_HMS): CF 999,958 · BLEVEL 2 · 리프 3,774블록 · 이 문제에서는 다른 인덱스가 없다(화면은 SHOP_NO와 ORD_HMS를 함께 읽으므로 테이블까지 간다)GATHER_TABLE_STATS 기본값(no_invalidate => DBMS_STATS.AUTO_INVALIDATE) · 히스토그램 없음CURSOR_SHARING = EXACT · 바인드 피킹 켬 · statistics_level = TYPICAL-- SalesDao.shopOrderCount(from, to) : 화면은 from = to = 전날, 월 정산 리포트는 한 달
SELECT SHOP_NO, COUNT(*) AS ORD_CNT, MIN(ORD_HMS) AS FIRST_HMS, MAX(ORD_HMS) AS LAST_HMS
FROM ORD_RANDOM
WHERE ORD_DT BETWEEN :f AND :t
GROUP BY SHOP_NO
[DBA_HIST_SQLSTAT — 같은 SQL_ID · 날마다]
요일 PLAN_HASH 실행 BUFFER_GETS/실행 커서가 다시 만들어진 시각 · 그때 온 호출
월 1648203117 2,031 1,975 04:12 · 화면(하루, 첫 점장)
화 3920571642 2,036 22,415 02:37 · 월 정산 리포트(한 달, 야간 예약 실행)
수 1648203117 2,029 1,974 05:48 · 화면(하루)
목 3920571642 2,033 22,416 03:05 · 월 정산 리포트(한 달)
[V$SQL_SHARED_CURSOR — 목요일 새 자식] ROLL_INVALID_MISMATCH = Y
[V$SQL — 목요일 자식] IS_BIND_SENSITIVE Y · IS_BIND_AWARE N · V$SQL_CS_HISTOGRAM 0:0 1:2,033 2:0
[목요일 자식 · 화면(하루) 한 번 · FORMAT 'ALLSTATS LAST +PEEKED_BINDS']
Plan hash value: 3920571642
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 200 |00:00:00.29 | 22414 | |
| 1 | HASH GROUP BY | | 1 | 200 | 200 |00:00:00.29 | 22414 | 1394K (0)|
|* 2 | FILTER | | 1 | | 1370 |00:00:00.28 | 22414 | |
|* 3 | TABLE ACCESS FULL | ORD_RANDOM | 1 | 41100 | 1370 |00:00:00.28 | 22414 | |
------------------------------------------------------------------------------------------------------------
Peeked Binds (identified by name):
----------------------------------
1 - :F (VARCHAR2(30), CSID=873): '20131101'
2 - :T (VARCHAR2(30), CSID=873): '20131130'
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:F<=:T)
3 - filter(("ORD_DT">=:F AND "ORD_DT"<=:T))
[수요일 자식 · 리포트(한 달) 한 번 · 이날 커서는 화면의 하루로 태어났다]
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 200 |00:00:00.61 | 41825 | |
| 1 | HASH GROUP BY | | 1 | 200 | 200 |00:00:00.61 | 41825 | 1394K (0)|
|* 2 | FILTER | | 1 | | 41666 |00:00:00.58 | 41825 | |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| ORD_RANDOM | 1 | 1370 | 41666 |00:00:00.57 | 41825 | |
|* 4 | INDEX RANGE SCAN | ORD_RANDOM_X01 | 1 | 1370 | 41666 |00:00:00.02 | 160 | |
------------------------------------------------------------------------------------------------------------
2 - filter(:F<=:T)
4 - access("ORD_DT">=:F AND "ORD_DT"<=:T)
[같은 날 화면(하루) 한 번 · 인덱스 계획] Buffers 1,377 · A-Time 0.01초