테마
버거 본사가 다른 브랜드의 매장 12곳을 인수했다. 그 매장들의 2013년 주문은 옛 POS 번호 체계라서, 이관팀이 스테이징 테이블에 받아 두고 본사 ORD와 ORD_ITEM으로 옮긴다. 새 주문 번호는 본사 POS와 같은 시퀀스 SQ_ORD_NO로 매긴다.
리허설에서 이관 프로그램이 5.7초 걸렸다. 올해 인수가 세 번 더 있고 다음 인수는 매장 수가 네 배다. 오과장이 시험 DB에서 안 네 개를 재 왔는데, D는 가장 빨랐지만 결과 건수가 이상했다. 박팀장: "하나를 골라 프로그램을 써 오고, 고른 안의 전제와 부작용까지 적어 줘요."
ORD 주문: 1,000,000행 · 22,422블록 · ORD_PK (ORD_NO) · ORD_X01 (ORD_DT, ORD_HMS) · ORD_NO는 시퀀스 SQ_ORD_NO(CACHE 20)로 매긴다 · 트리거 없음ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS)STG_ORD 인수 매장 주문(이 문제용): 41,200행 · OLD_ORD_KEY VARCHAR2(20)(옛 POS 번호) · ORD_DT · ORD_HMS · SHOP_NO · PK (OLD_ORD_KEY)STG_ORD_ITEM 인수 매장 주문상품(이 문제용): 102,957행 · OLD_ORD_KEY · ITEM_ID · ORD_ITEM_QTY · PK (OLD_ORD_KEY, ITEM_ID)PROCEDURE P_MIG_ACQ IS
v_no ORD.ORD_NO%TYPE;
BEGIN
FOR o IN (SELECT OLD_ORD_KEY, ORD_DT, ORD_HMS, SHOP_NO FROM STG_ORD) LOOP
SELECT SQ_ORD_NO.NEXTVAL INTO v_no FROM dual; -- 주문마다 새 번호
INSERT INTO ORD (ORD_NO, ORD_DT, ORD_HMS, SHOP_NO)
VALUES (v_no, o.ORD_DT, o.ORD_HMS, o.SHOP_NO);
FOR i IN (SELECT ITEM_ID, ORD_ITEM_QTY
FROM STG_ORD_ITEM
WHERE OLD_ORD_KEY = o.OLD_ORD_KEY) LOOP
INSERT INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS)
VALUES (v_no, i.ITEM_ID, i.ORD_ITEM_QTY, o.ORD_DT, o.ORD_HMS);
END LOOP;
END LOOP;
COMMIT;
END;
[세션 통계 — 리허설 (주문 41,200 · 주문상품 102,957)]
경과 5.7 초 · recursive calls 311,437 · session logical reads 878,412 · redo size 71 MB
[TKPROF — 루프 안의 문장 (dep=1)]
call count query current rows
SELECT SQ_ORD_NO.NEXTVAL FROM DUAL Execute 41,200 0 0 0
Fetch 41,200 0 0 41,200
INSERT INTO ORD (…) VALUES (:B4, :B3, :B2, :B1) Execute 41,200 1,214 170,388 41,200
SELECT ITEM_ID, ORD_ITEM_QTY FROM STG_ORD_ITEM Execute 41,200 0 0 0
WHERE OLD_ORD_KEY = :B1 Fetch 41,200 164,800 0 102,957
INSERT INTO ORD_ITEM (…) VALUES (:B5, …) Execute 102,957 3,018 521,646 102,957
update seq$ … (dep=2) Execute 2,060 2,060 4,120 2,060
[오과장의 네 안 — 시험 DB · 같은 41,200건]
안 경과 recursive calls redo 결과 (ORD / ORD_ITEM)
A 지금 판 (주문마다 NEXTVAL, 줄마다 INSERT) 5.7 초 311,437 71 MB 41,200 / 102,957
B FORALL INSERT … RETURNING BULK COLLECT (1,000건씩) 0.9 초 2,247 52 MB 41,200 / 102,957
C 스테이징에 새 번호를 먼저 매기고 INSERT … SELECT 두 문장 0.6 초 2,151 58 MB 41,200 / 102,957
D INSERT ALL (STG_ORD ⋈ STG_ORD_ITEM이 원천, NEXTVAL과 CURRVAL) 0.5 초 5,231 67 MB 102,957 / 102,957
[D의 문장]
INSERT ALL
INTO ORD (ORD_NO, ORD_DT, ORD_HMS, SHOP_NO) VALUES (SQ_ORD_NO.NEXTVAL, ORD_DT, ORD_HMS, SHOP_NO)
INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS) VALUES (SQ_ORD_NO.CURRVAL, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS)
SELECT o.ORD_DT, o.ORD_HMS, o.SHOP_NO, i.ITEM_ID, i.ORD_ITEM_QTY
FROM STG_ORD o, STG_ORD_ITEM i
WHERE i.OLD_ORD_KEY = o.OLD_ORD_KEY;
→ 205,914 rows created (에러 없음)