테마
버거 본사는 메뉴 코드를 정정할 때마다 「일별 상품 판매 집계」를 2년 치 전부 다시 계산한다. 한 세션으로 43분 걸리던 일을, 지난달 개발팀이 매장 번호로 네 갈래로 나눠 잡 넷이 동시에 돌도록 바꿨다(MOD(매장 번호, 4)).
7월 3일 22:10에 처음 돌렸더니 잡 넷 가운데 셋이 ORA-00060으로 죽었다. 담당자가 다음 날 죽은 잡 셋을 처음부터 다시 돌렸고 이번에는 끝까지 돌았다. 그런데 2012년 초의 판매 수량이 POS 보고서보다 훨씬 많다.
ORD 주문: 1,000,000행 · 22,422블록 · SHOP_NO VARCHAR2 'SH0001' ~ 'SH0200' · ORD_PK (ORD_NO)ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_NO · ITEM_ID · ORD_ITEM_QTY · ORD_DT · ORD_ITEM_PK (ORD_NO, ITEM_ID)ITEM_DAY_SUM 일별 상품 판매 집계(이 문제의 파생 테이블): 상품 92개 × 730일 = 67,160행 · 약 250블록 · PK (ITEM_ID, ORD_DT) · SALE_QTY-- 0단계 (한 번): 집계를 0으로
UPDATE ITEM_DAY_SUM SET SALE_QTY = 0;
COMMIT;
-- 1단계: 잡 넷 (p_part = 0 · 1 · 2 · 3) 을 동시에
PROCEDURE RECALC_PART(p_part NUMBER) IS
n PLS_INTEGER := 0;
BEGIN
FOR r IN (SELECT i.ITEM_ID, i.ORD_DT, i.ORD_ITEM_QTY
FROM ORD o, ORD_ITEM i
WHERE i.ORD_NO = o.ORD_NO
AND MOD(TO_NUMBER(SUBSTR(o.SHOP_NO, 3)), 4) = p_part
ORDER BY o.ORD_NO) LOOP
UPDATE ITEM_DAY_SUM
SET SALE_QTY = SALE_QTY + r.ORD_ITEM_QTY
WHERE ITEM_ID = r.ITEM_ID AND ORD_DT = r.ORD_DT;
n := n + 1;
IF MOD(n, 1000) = 0 THEN COMMIT; END IF;
END LOOP;
COMMIT;
END;
[잡 넷 — 7월 3일 22:10 시작 (0단계로 67,160행을 0으로 만든 뒤)]
잡 SID 매장 처리할 줄 결과
J0 330 50곳 618,204 끝 · 23:01 (51분)
J1 301 50곳 619,515 ORA-00060 · 22:14:07 · 52,000줄을 COMMIT 한 뒤 죽음
J2 288 50곳 617,880 ORA-00060 · 22:19:52 · 127,000줄을 COMMIT 한 뒤 죽음
J3 317 50곳 617,118 ORA-00060 · 22:27:30 · 211,000줄을 COMMIT 한 뒤 죽음
(한 세션으로 돌리던 지난달까지: 2,472,717줄 · 43분)
[V$SESSION — 22:12:00 · 넷 다 같은 문장]
SID EVENT SECS BLOCKING_SESSION
301 enq: TX - row lock contention 2 288
288 enq: TX - row lock contention 1 330
317 enq: TX - row lock contention 3 301
330 (CPU)
하고 있는 문장: UPDATE ITEM_DAY_SUM SET SALE_QTY = SALE_QTY + :B3 WHERE ITEM_ID = :B2 AND ORD_DT = :B1
[J1 (SID 301) 의 트레이스 — Deadlock graph]
Resource Name process session holds waits process session holds waits
TX-000A0015-00001F2C-469D09C8-... 52 317 X 47 301 X
TX-0003001B-00002A61-469D09C8-... 47 301 X 52 317 X
Rows waited on:
Session 301: ITEM_DAY_SUM · ITEM_ID 12 · ORD_DT '20120115'
Session 317: ITEM_DAY_SUM · ITEM_ID 7 · ORD_DT '20120115'
[J0 (SID 330) — 세션 통계]
UPDATE 실행 618,204번 · user commits 619 · enq: TX 기다림 2,914번 · 합계 31분 (경과 51분의 61%)
[다시 돌린 뒤 — POS 보고서와 비교한 판매 수량]
2012년 1 ~ 2월 1.75배 · 3 ~ 5월 1.5배 · 6 ~ 8월 1.25배 · 9월 초부터 같음
V$SESSION, 트레이스를 근거로 매장 번호로 나눈 잡끼리 왜 서로 기다리고 원을 만드는지 설명하시오. 다시 돌린 뒤 숫자가 늘어난 이유도 쓰시오.