Skip to content
튜닝 연습Lock과 동시성 제어
LOCK-007

자동발주 배치가 도는 3분 동안 물류센터 입고 화면이 멈춘다

기초PLSQL유통502 / 700

상황 ​

본사 레거시 유통의 자동발주 배치는 매일 17:30에 재고가 기준 아래로 떨어진 상품을 모아 발주 60건 안팎을 만든다. 한 트랜잭션으로 돌고 약 3분 걸린다. 지난주부터 그 3분 동안 물류센터의 「입고 확인」 화면(발주 진행 코드를 입고 완료로 바꾼다)이 저장 버튼에서 멈춘다. 2주 전에 번호 받기 함수를 고친 사람은 이렇게 적어 두었다. "발주번호가 두 번 겹쳐서 LOCK TABLE 추가 (MAX에 FOR UPDATE는 ORA-01786)."

테이블과 인덱스 ​

  • CF12 발주: 734행 · 10블록 · CF12_PK (ORD_NO) · ORD_DT VARCHAR2(8) · ORD_PRGS_CD 발주 진행 코드
  • 발주번호 ORD_NO: 발주일자 여덟 자리와 그날의 두 자리 일련번호(예 '2023010205') · 날마다 01부터 다시 시작한다
  • CF13 발주상품: 7,102행 · 57블록 · PK (ORD_NO, ITM_NO)
  • 본사 MD도 낮에 화면에서 발주를 하루 몇 건 손으로 등록한다(같은 번호 체계, 같은 함수)
  • 「입고 확인」 화면: UPDATE CF12 SET ORD_PRGS_CD = :cd WHERE ORD_NO = :no · 17:00 ~ 18:00이 가장 바쁘다

원본 SQL ​

sql
-- PKG_PO.NEW_ORDER_NO — 자동발주 배치와 MD 화면이 같이 부른다 (COMMIT 은 부른 쪽이 한다)
FUNCTION NEW_ORDER_NO(p_dt VARCHAR2) RETURN VARCHAR2 IS
  v_no CF12.ORD_NO%TYPE;
BEGIN
  LOCK TABLE CF12 IN EXCLUSIVE MODE;            -- 번호가 겹쳐서 추가 (2주 전)
  SELECT p_dt || LPAD(NVL(MAX(SUBSTR(ORD_NO, 9, 2)), '00') + 1, 2, '0')
    INTO v_no
    FROM CF12
   WHERE ORD_DT = p_dt;
  RETURN v_no;
END;

-- 자동발주 배치 (17:30 · 한 트랜잭션)
FOR r IN (SELECT PTNR_NO FROM … /* 기준 미달 상품을 거래처별로 묶은 60 건 */) LOOP
  v_no := NEW_ORDER_NO(:today);
  INSERT INTO CF12 (ORD_NO, ORD_DT, PTNR_NO, ORD_PRGS_CD) VALUES (v_no, :today, r.PTNR_NO, '10');
  INSERT INTO CF13 (ORD_NO, ITM_NO, ORD_QTY) SELECT v_no, … ;
END LOOP;
COMMIT;

실행계획 학습용 예시 ​

xplan
[V$SESSION — 17:31:40 · 배치가 돈 지 100초]
SID   EVENT                            SECS   BLOCKING_SESSION   하는 문장
212   db file sequential read             0                      INSERT INTO CF13 …                    (자동발주 배치)
57    enq: TM - contention               88   212                UPDATE CF12 SET ORD_PRGS_CD …          (입고 확인 1)
63    enq: TM - contention               61   212                UPDATE CF12 SET ORD_PRGS_CD …          (입고 확인 2)
81    enq: TM - contention               14   212                LOCK TABLE CF12 IN EXCLUSIVE MODE     (MD 발주 등록)

[V$LOCK — 같은 시각]
SID   TYPE  대상                   LMODE  REQUEST  BLOCK
212   TM    CF12                     6      0        1      ← LOCK TABLE … EXCLUSIVE · COMMIT 까지
212   TM    CF13                     3      0        0
212   TX    212 의 트랜잭션           6      0        0
57    TM    CF12                     0      3        0
63    TM    CF12                     0      3        0
81    TM    CF12                     0      6        0

[17:30 ~ 17:33 · 배치 한 번]
  발주 61건 · 발주번호 '2023121501' ~ '2023121561' · 입고 확인 대기 최대 172초
  입고 확인 화면의 조회(SELECT)는 막히지 않았다 · 배치가 COMMIT 하자 기다리던 UPDATE 가 한꺼번에 풀렸다

문제 ​

  1. V$LOCK을 보고 입고 확인 화면이 무엇을 기다리는지, 왜 배치가 끝날 때까지 풀리지 않는지 설명하시오.
  2. 발주번호가 겹치지 않으면서 입고 확인 화면을 막지 않도록 번호 받기를 고치시오. 바꾼 뒤에도 남는 기다림이 있다면 무엇인지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자