Skip to content
튜닝 연습PL/SQL과 사용자 정의 함수
PLSQL-023

반송함에 적힌 주문을 찾아가 보면 멀쩡히 정산돼 있다

중급PLSQL한빛유통673 / 700

상황 ​

정산 적재(P1)의 새 판은 BULK COLLECT와 FORALL로 짰다. 취소 주문은 받은 배열에서 지우고(DELETE(i)) INDICES OF로 넣으며, 넣다가 실패한 주문은 SAVE EXCEPTIONS로 받아 반송함에 남긴다. 리허설에서 빨라진 것을 확인하고 이번 달부터 운영에 올렸다. 정산팀 조민우가 문의했다. "반송함에 3건이 있어서 찾아가 봤는데, 그 주문들은 정산에 멀쩡히 들어가 있어요. 그런데 정산 건수는 3건이 모자라요."

테이블과 인덱스 ​

  • T_ORD 주문: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ) · ORD_SEQ 1 ~ 100,000 · 취소(ORD_ST = 'CANCEL')는 ORD_SEQ가 50의 배수인 2,000건
  • 이번 달에는 전액 쿠폰으로 결제해 ORD_AMT가 0인 주문이 3건 있다(36,512 · 71,248 · 88,937).
  • T_ORD_STLM 정산: 배치 시작 때 TRUNCATE · CHECK (STLM_AMT > 0) 제약이 있다(이 문제용)
  • T_STLM_REJ 반송함: ORD_SEQ · ERR_CD VARCHAR2(10) · RUN_DT

원본 SQL ​

sql
PROCEDURE P1_LOAD_V2 IS
  CURSOR c IS SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_ST, ORD_AMT FROM T_ORD ORDER BY ORD_SEQ;
  TYPE t_rows IS TABLE OF c%ROWTYPE INDEX BY PLS_INTEGER;
  v        t_rows;
  v_ix     PLS_INTEGER;
  v_cd     PLS_INTEGER;
  bulk_err EXCEPTION;
  PRAGMA EXCEPTION_INIT(bulk_err, -24381);
BEGIN
  EXECUTE IMMEDIATE 'TRUNCATE TABLE T_ORD_STLM';
  OPEN c;
  LOOP
    FETCH c BULK COLLECT INTO v LIMIT 1000;
    EXIT WHEN v.COUNT = 0;
    FOR i IN 1 .. v.COUNT LOOP
      IF v(i).ORD_ST = 'CANCEL' THEN v.DELETE(i); END IF;        -- 취소 주문은 배열에서 뺀다
    END LOOP;
    BEGIN
      FORALL i IN INDICES OF v SAVE EXCEPTIONS
        INSERT INTO T_ORD_STLM (STLM_SEQ, ORD_SEQ, CUS_ID, STLM_DT, STLM_AMT)
        VALUES (v(i).ORD_SEQ, v(i).ORD_SEQ, v(i).CUS_ID, v(i).ORD_DT, v(i).ORD_AMT);
    EXCEPTION
      WHEN bulk_err THEN
        FOR j IN 1 .. SQL%BULK_EXCEPTIONS.COUNT LOOP
          v_ix := SQL%BULK_EXCEPTIONS(j).ERROR_INDEX;
          v_cd := SQL%BULK_EXCEPTIONS(j).ERROR_CODE;
          INSERT INTO T_STLM_REJ (ORD_SEQ, ERR_CD, RUN_DT)
          VALUES (v(v_ix).ORD_SEQ, v_cd, SYSDATE);
        END LOOP;
    END;
  END LOOP;
  CLOSE c;
  COMMIT;
END;

실행계획 학습용 예시 ​

xplan
[이번 달 실행 결과]
  원천 T_ORD                    100,000
  취소 (배열에서 지움)            2,000
  정산 T_ORD_STLM                97,997
  반송함 T_STLM_REJ                  3    ERR_CD 2290 (ORA-02290: check constraint violated)
  경과 0.31 초 · recursive calls 214 · FORALL 실행 100번

[반송함 3건을 정산과 대조]
  반송함 ORD_SEQ   정산에 있나   ORD_AMT
         36,502        있다       184,300
         71,244        있다        92,700
         88,919        있다       311,500

[취소도 아닌데 정산에도 반송함에도 없는 주문]
         36,512                         0
         71,248                         0
         88,937                         0

문제 ​

  1. 반송함에 엉뚱한 주문이 적힌 이유를 SQL%BULK_EXCEPTIONS(j).ERROR_INDEX의 뜻으로 설명하시오. 36,512가 36,502로 적힌 까닭을 숫자로 보이시오.
  2. 정산 결과와 반송함이 맞게 프로시저를 고치시오. 배치가 끝날 때 빠진 주문이 없는지 스스로 확인하게 하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자