테마
버거 본사는 2013년 4월부터 주문 한 건에 상품을 20종까지만 받는다(주방 화면 한 장에 20줄이 들어간다). POS가 상품 줄을 한 줄씩 넣던 때 만든 트리거 TRG_ORD_ITEM_MAX가 줄을 넣기 전에 그 주문의 줄 수를 센다.
2013년 12월 POS 중계 서버를 들이면서 상품 줄은 중계 테이블에서 1분마다 INSERT … SELECT로 들어오게 됐다. 첫날 중계 적재가 ORA-04091로 실패하자 개발자가 트리거에 PRAGMA AUTONOMOUS_TRANSACTION 한 줄을 붙였고, 에러가 사라졌다. 오늘 감사팀이 37종짜리 주문을 찾아 왔다.
ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID)(리프 약 6,600블록) · 주문 1,000,000건, 주문당 평균 2.5종POS_RELAY_ITEM 중계 테이블(이 문제용): 중계 서버가 결제가 끝난 주문의 상품 줄을 모아 1분마다 회차(RELAY_NO)를 매긴다 · 하루 1,440회차 · 약 3,390줄ORD_NO는 NUMBER다.CREATE OR REPLACE TRIGGER TRG_ORD_ITEM_MAX
BEFORE INSERT ON ORD_ITEM
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION; -- 2013.12.02 중계 적재의 ORA-04091 때문에 붙였다
v_cnt PLS_INTEGER;
BEGIN
SELECT COUNT(*) INTO v_cnt FROM ORD_ITEM WHERE ORD_NO = :NEW.ORD_NO;
IF v_cnt >= 20 THEN
RAISE_APPLICATION_ERROR(-20021, '주문 ' || :NEW.ORD_NO || '의 상품이 20종을 넘는다');
END IF;
END;
/
-- POS 중계 적재 (1분마다 한 회차)
INSERT INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS)
SELECT ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS
FROM POS_RELAY_ITEM
WHERE RELAY_NO = :relay_no;
COMMIT;
[2013-12-02 개발자 메모]
중계 적재 실패 → ORA-04091: table DEV.ORD_ITEM is mutating, trigger/function may not see it
트리거에 PRAGMA AUTONOMOUS_TRANSACTION 한 줄 → 에러 사라짐
[오늘 — 감사팀 점검]
상품이 20종을 넘는 주문 23건 · 모두 2013-12-02 이후 · 가장 큰 주문 37종
[시험 DB — 21종짜리 주문 한 건을 중계 테이블에 넣고 같은 적재]
21 rows created (에러 없음)
트리거가 센 v_cnt (디버그 출력) : 21번 모두 0
[TKPROF — 하루치 중계 적재 (INSERT … SELECT 1,440번 · 3,391줄)]
SELECT COUNT(*) FROM ORD_ITEM WHERE ORD_NO = :B1 (dep=1 · 자율 트랜잭션 안)
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 3391 0.19 0.22 0 0 0 0
Fetch 3391 0.07 0.09 0 10173 0 3391