테마
화요일 14:01, 개발자가 판매가 패키지 PKG_PRICE 본문의 할인 규칙 한 줄을 고쳐 SQL Developer에서 배포했다(CREATE OR REPLACE PACKAGE BODY). 배포 창이 4분 넘게 멈춰 있는 동안 매장 POS의 「상품 상세」와 본사 ERP 가격 화면이 모두 멈췄다.
14:05:53에 배포가 끝나자 화면이 풀렸고, 이어 1분 동안 ERP와 POS 화면 40곳에서 ORA-04068이 한 번씩 떴다. 박팀장: "원인을 정리하고, 다시는 이런 일이 없게 패키지 구조와 배포 절차를 고쳐 와요. 무엇을 함께 쓸지도 정해 주고요."
PKG_PRICE 판매가 패키지: CUR_UPRC(itm_no) 현재 판매가(POS 「상품 상세」 하루 3,000번, ERP 가격 화면) · RECALC_MONTH(ym) 월 판매가 재집계(판매상품마다 CUR_UPRC를 불러 점검 테이블에 쓴다, 한 번에 4 ~ 5분)RECALC_MONTH는 매월 둘째 화요일 14:00에 스케줄러가 돌린다.g_last_itm, g_last_uprc가 있다(직전에 물은 상품의 답을 기억한다. POS 호출에서 맞힌 비율은 3%다).CF05 상품가격: 157행 · PK(ITM_NO, UPRC_KN_CD, APL_DT) · 판매가는 UPRC_KN_CD = '01'CREATE OR REPLACE PACKAGE BODY PKG_PRICE IS
g_last_itm NUMBER; -- 직전에 물은 상품 (2018)
g_last_uprc NUMBER; -- 그 답
FUNCTION CUR_UPRC(p_itm_no NUMBER) RETURN NUMBER IS
v NUMBER;
BEGIN
IF p_itm_no = g_last_itm THEN
RETURN g_last_uprc;
END IF;
SELECT MAX(ITM_UPRC) KEEP (DENSE_RANK LAST ORDER BY APL_DT) INTO v
FROM CF05
WHERE ITM_NO = p_itm_no
AND UPRC_KN_CD = '01'
AND APL_DT <= TO_CHAR(SYSDATE, 'YYYYMMDD');
v := ROUND(v * 0.95); -- 할인 규칙 (화요일 14:01에 고친 줄)
g_last_itm := p_itm_no;
g_last_uprc := v;
RETURN v;
END;
PROCEDURE RECALC_MONTH(p_ym VARCHAR2) IS -- 월 판매가 재집계 (4 ~ 5분)
BEGIN
NULL; -- … 판매상품마다 CUR_UPRC를 불러 점검 테이블에 쓴다 (생략)
END;
END;
/
[14:03 V$SESSION — 대기 중인 세션 (요약)]
SID 누구 EVENT BLOCKING_SESSION SECONDS_IN_WAIT
87 스케줄러 RECALC_MONTH (14:00 시작) (CPU · 실행 중) — —
142 SQL Developer (배포) library cache pin 87 85
33 ERP WAS library cache lock 142 81
35 ERP WAS library cache lock 142 77
… (WAS 세션 31개 더 · 모두 library cache lock · BLOCKING_SESSION 142)
[14:03 V$ACCESS — PKG_PRICE를 쥐고 있는 세션 (ACTIVE만)]
SID 87 · OBJECT PKG_PRICE · TYPE PACKAGE, PACKAGE BODY
[시간표]
14:00:02 RECALC_MONTH 시작
14:01:38 배포 시작 (CREATE OR REPLACE PACKAGE BODY PKG_PRICE)
14:05:52 RECALC_MONTH 끝
14:05:53 배포 끝 → 기다리던 화면 세션이 모두 풀림
14:05 ~ 14:07 화면 오류 40건 (세션마다 한 번)
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "PUP.PKG_PRICE" has been invalidated