테마
버거 품질팀은 리콜에 대비해 주문 상품을 개수 단위로 한 줄씩 남긴다(ITEM_UNIT_TRC). 수량 3개짜리 주문상품은 1번, 2번, 3번 세 줄이 된다. 지난주 원천 정정으로 2013년 12월 한 달을 다시 만들었는데, 품질팀이 "12월 이력이 주문상품 수량 합계보다 2,835개 적다"라고 알려 왔다. 적재는 3초가 걸린다.
적재 SQL은 5년 전 "수량은 많아야 5개"라는 말을 듣고 짠 것이다. 지금은 단체 주문이 늘어 한 줄 수량이 수십 개인 주문상품도 있다.
ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_NO · ITEM_ID · ORD_ITEM_QTY · ORD_DT · ORD_HMS · PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS): 날짜순으로 쌓여 있어 한 달 범위를 읽기 좋다ITEM_UNIT_TRC 개수 단위 이력 (이 문제에서 쓰는 파생 테이블): ORD_NO · ITEM_ID · UNIT_SEQ · ORD_DT · PK (ORD_NO, ITEM_ID, UNIT_SEQ) · 다시 만들 달은 먼저 지운다 · 야간에만 적재한다:d1, :d2, 'YYYYMMDD')을 넘긴다INSERT INTO ITEM_UNIT_TRC (ORD_NO, ITEM_ID, UNIT_SEQ, ORD_DT)
SELECT ORD_NO, ITEM_ID, 1, ORD_DT FROM ORD_ITEM
WHERE ORD_DT BETWEEN :d1 AND :d2 AND ORD_ITEM_QTY >= 1
UNION ALL
SELECT ORD_NO, ITEM_ID, 2, ORD_DT FROM ORD_ITEM
WHERE ORD_DT BETWEEN :d1 AND :d2 AND ORD_ITEM_QTY >= 2
UNION ALL
SELECT ORD_NO, ITEM_ID, 3, ORD_DT FROM ORD_ITEM
WHERE ORD_DT BETWEEN :d1 AND :d2 AND ORD_ITEM_QTY >= 3
UNION ALL
SELECT ORD_NO, ITEM_ID, 4, ORD_DT FROM ORD_ITEM
WHERE ORD_DT BETWEEN :d1 AND :d2 AND ORD_ITEM_QTY >= 4
UNION ALL
SELECT ORD_NO, ITEM_ID, 5, ORD_DT FROM ORD_ITEM
WHERE ORD_DT BETWEEN :d1 AND :d2 AND ORD_ITEM_QTY >= 5
[INSERT 안의 SELECT만 떼어 돌린 계획 · 2013년 12월]
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 147853 | 00:00:00.29 | 13450 |
| 1 | UNION-ALL | | 1 | | 147853 | 00:00:00.29 | 13450 |
|* 2 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD_ITEM | 1 | 103K | 104860 | 00:00:00.07 | 2690 |
|* 3 | INDEX RANGE SCAN | ORD_ITEM_X01 | 1 | 103K | 104860 | 00:00:00.01 | 346 |
|* 4 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD_ITEM | 1 | 29K | 29361 | 00:00:00.06 | 2690 |
|* 5 | INDEX RANGE SCAN | ORD_ITEM_X01 | 1 | 103K | 104860 | 00:00:00.01 | 346 |
|* 6 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD_ITEM | 1 | 9300 | 9437 | 00:00:00.06 | 2690 |
|* 7 | INDEX RANGE SCAN | ORD_ITEM_X01 | 1 | 103K | 104860 | 00:00:00.01 | 346 |
|* 8 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD_ITEM | 1 | 3100 | 3146 | 00:00:00.05 | 2690 |
|* 9 | INDEX RANGE SCAN | ORD_ITEM_X01 | 1 | 103K | 104860 | 00:00:00.01 | 346 |
|* 10 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD_ITEM | 1 | 1030 | 1049 | 00:00:00.05 | 2690 |
|* 11 | INDEX RANGE SCAN | ORD_ITEM_X01 | 1 | 103K | 104860 | 00:00:00.01 | 346 |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ORD_ITEM_QTY">=1)
3 - access("ORD_DT">=:D1 AND "ORD_DT"<=:D2)
4 - filter("ORD_ITEM_QTY">=2)
5 - access("ORD_DT">=:D1 AND "ORD_DT"<=:D2)
(6 ~ 11번 줄도 같은 모양 · 수량 조건만 3, 4, 5)
[적재 전체] 3.02초 · 이력 147,853행 (SELECT 0.29초 + 테이블과 PK 인덱스에 넣는 일 2.73초)