테마
버거원 본사 영업기획팀의 「매장별 상품 판매」 반기 리포트(2013년 하반기)는 원래 새벽 02:00에 돌고 31분 걸린다. 지난주 화요일 급한 보고 때문에 14:00에 돌렸더니 23분 만에 ORA-01555: snapshot too old로 죽었다. 두 번 더 돌렸지만 두 번 다 20분을 넘기고 죽었다.
DBA는 언두 테이블스페이스를 두 배로 늘리자고 했다. 리포트 SQL 맨 위에는 "NL 고정. 매장별로 읽어야 빠름(2012.03, 매장 30곳)"이라는 주석과 힌트가 있다.
ORD 주문: 1,000,000행 · 22,422블록 · ORD_DT VARCHAR2(8) · 2013년 하반기 약 252,000건 · 인덱스 ORD_X01 (ORD_DT, ORD_HMS), 이 문제에서 더한 ORD_X02 (SHOP_NO, ORD_DT)ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_DT는 주문의 ORD_DT를 그대로 복사한 칸이다 · 2013년 하반기 약 623,000행SHOP 매장: 200행 · 5블록ORD, ORD_ITEM 행을 분당 수십 건 고치고 COMMIT한다. 새벽에는 거의 없다.undo_retention 900 · 버퍼 캐시 1GB-- 「매장별 상품 판매」 반기 리포트
-- NL 고정. 매장별로 읽어야 빠름 (2012.03, 매장 30곳)
SELECT /*+ LEADING(s o i) USE_NL(o) USE_NL(i) INDEX(o ORD_X02) */
s.SHOP_NO, s.SHOP_NM, i.ITEM_ID,
SUM(i.ORD_ITEM_QTY) AS QTY
FROM SHOP s, ORD o, ORD_ITEM i
WHERE o.SHOP_NO = s.SHOP_NO
AND o.ORD_DT BETWEEN '20130701' AND '20131231'
AND i.ORD_NO = o.ORD_NO
GROUP BY s.SHOP_NO, s.SHOP_NM, i.ITEM_ID;
[새벽 02:00 — 끝까지 돈 실행 · ALLSTATS LAST]
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
--------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 18210 | 00:31:04.12 | 1265K | 412K |
| 1 | HASH GROUP BY | | 1 | 18400 | 18210 | 00:31:04.12 | 1265K | 412K |
| 2 | NESTED LOOPS | | 1 | 618K | 623K | 00:30:58.40 | 1265K | 412K |
| 3 | NESTED LOOPS | | 1 | 250K | 252K | 00:09:12.77 | 253K | 121K |
| 4 | TABLE ACCESS FULL | SHOP | 1 | 200 | 200 | 00:00:00.01 | 5 | 0 |
| 5 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD | 200 | 1250 | 252K | 00:09:12.70 | 253K | 121K |
|* 6 | INDEX RANGE SCAN | ORD_X02 | 200 | 1250 | 252K | 00:00:01.90 | 1420 | 410 |
| 7 | TABLE ACCESS BY INDEX ROWID | ORD_ITEM | 252K | 2 | 623K | 00:21:40.10 | 1012K | 291K |
|* 8 | INDEX RANGE SCAN | ORD_ITEM_PK | 252K | 2 | 623K | 00:06:02.30 | 758K | 97K |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("O"."SHOP_NO"="S"."SHOP_NO" AND "O"."ORD_DT">='20130701' AND "O"."ORD_DT"<='20131231')
8 - access("I"."ORD_NO"="O"."ORD_NO")
[14:00 — 알림 로그]
ORA-01555 caused by SQL statement below (SQL ID: 4hq7d2w9n3c8k, Query Duration=1380 sec, SCN: 0x00000000b71c04e2):
SELECT /*+ LEADING(s o i) USE_NL(o) USE_NL(i) INDEX(o ORD_X02) */ S.SHOP_NO, S.SHOP_NM, I.ITEM_ID, SUM(I.ORD_ITEM_QTY) …
같은 날 세 번: 14:00 → 14:23 · 14:25 → 14:47 · 14:50 → 15:12
[V$UNDOSTAT — 10분 구간]
구간 UNDOBLKS TXNCOUNT MAXQUERYLEN TUNED_UNDORETENTION UNXPSTEALCNT SSOLDERRCNT
02:00 ~ 02:40 3,120 410 1,864 21,400 0 0
14:00 ~ 15:10 418,200 61,400 1,380 1,040 0 3
V$UNDOSTAT으로 설명하시오. 이 리포트는 아무것도 고치지 않는데 왜 언두가 필요한지도 쓰시오.