Skip to content
튜닝 연습DML과 배치 튜닝
DML-066

PG 정산 파일 10만 줄을 올리는 데 41초, 금액에 쉼표가 든 214줄은 오류 테이블로 빠진다

중급INSERT한빛유통491 / 700

상황 ​

한빛유통은 매일 01:30에 PG사가 보내는 전날 결제 정산 파일(CSV, 약 10만 줄)을 대사용 테이블 T_PG_STLM에 올린다. 2020년에 만든 프로시저가 UTL_FILE로 한 줄씩 읽고 쉼표로 잘라 한 행씩 INSERT한다. 파일이 커지면서 적재가 41초로 늘었다. 지난달부터는 매일 200여 줄이 오류 테이블 T_PG_LOAD_ERR로 빠진다. PG사가 금액 칸을 "12,900"처럼 따옴표로 감싸고 천 단위 쉼표를 넣기 시작한 뒤부터다. 조민우: "오류 난 줄은 아침마다 제가 손으로 넣고 있어요."

테이블과 인덱스 ​

  • 파일 pg_stlm_YYYYMMDD.csv: DB 서버의 디렉터리 객체 PG_DIR에 PG사가 올린다. 첫 줄은 머리글이다. 10월 28일 파일은 거래 102,000줄(약 9.8MB)이다. 칸은 거래번호, 주문번호, 거래일시(2024-10-28 13:05:41), 거래구분(A 승인, C 취소), 금액, 수수료 순이다.
  • T_PG_STLM(이 문제용): PG_TID VARCHAR2(20) · ORD_SEQ NUMBER · TRX_DTT DATE · TRX_TP VARCHAR2(1) · TRX_AMT NUMBER · FEE_AMT NUMBER · LOAD_DT DATE · PK PK_T_PG_STLM (PG_TID) · 날마다 약 10만 행이 쌓이고 지우지 않는다. 낮에는 대사 화면이 읽기만 한다. 트리거와 FK는 없다.
  • T_PG_LOAD_ERR: 넣지 못한 줄과 오류 메시지를 남기는 테이블
  • 운영 DB(19c)는 ARCHIVELOG이고 T_PG_STLM은 LOGGING이다. 01:30 ~ 02:30에는 이 테이블을 쓰는 다른 세션이 없다.

원본 SQL ​

sql
PROCEDURE P_PG_LOAD(p_dt VARCHAR2) IS                         -- p_dt = '20241028'
  f       UTL_FILE.FILE_TYPE;
  v_line  VARCHAR2(400);
  n       PLS_INTEGER := 0;
BEGIN
  f := UTL_FILE.FOPEN('PG_DIR', 'pg_stlm_' || p_dt || '.csv', 'r');
  UTL_FILE.GET_LINE(f, v_line);                                 -- 머리글 건너뛰기
  LOOP
    BEGIN
      UTL_FILE.GET_LINE(f, v_line);
    EXCEPTION
      WHEN NO_DATA_FOUND THEN EXIT;                             -- 파일 끝
    END;
    BEGIN
      INSERT INTO T_PG_STLM (PG_TID, ORD_SEQ, TRX_DTT, TRX_TP, TRX_AMT, FEE_AMT, LOAD_DT)
      VALUES (REGEXP_SUBSTR(v_line, '[^,]+', 1, 1),
              TO_NUMBER(REGEXP_SUBSTR(v_line, '[^,]+', 1, 2)),
              TO_DATE(REGEXP_SUBSTR(v_line, '[^,]+', 1, 3), 'YYYY-MM-DD HH24:MI:SS'),
              REGEXP_SUBSTR(v_line, '[^,]+', 1, 4),
              TO_NUMBER(REGEXP_SUBSTR(v_line, '[^,]+', 1, 5)),
              TO_NUMBER(REGEXP_SUBSTR(v_line, '[^,]+', 1, 6)),
              SYSDATE);
      n := n + 1;
      IF MOD(n, 1000) = 0 THEN COMMIT; END IF;
    EXCEPTION
      WHEN OTHERS THEN
        INSERT INTO T_PG_LOAD_ERR (LOAD_DT, LINE_TXT, ERR_MSG) VALUES (SYSDATE, v_line, SQLERRM);
    END;
  END LOOP;
  UTL_FILE.FCLOSE(f);
  COMMIT;
END;

실행계획 학습용 예시 ​

xplan
[10월 28일 적재 — 세션 통계]
  경과 시간                       41.3 초
  CPU used by this session        33.8 초
  UTL_FILE.GET_LINE 호출          102,002
  INSERT 실행 (T_PG_STLM)         102,000   (성공 101,786 · 실패 214)
  INSERT 실행 (T_PG_LOAD_ERR)     214
  user commits                    102
  redo size                       약 34.6 MB
  undo change vector size         약 7.2 MB

[DBMS_HPROF — 시간이 쓰인 곳]
  T_PG_STLM INSERT (SQL · 줄마다 REGEXP_SUBSTR 여섯 번 포함)   102,000 부름   29.7 초
  UTL_FILE.GET_LINE                                            102,002 부름    6.4 초
  COMMIT                                                           102 부름    1.2 초
  나머지 (PL/SQL 루프 · 예외 처리)                                             4.0 초

[T_PG_LOAD_ERR — 10월 28일]
  214줄 · 모두 ORA-01722: invalid number · 모두 금액이 "12,900"처럼 따옴표와 쉼표로 온 줄
  예) T2410280000123,88213,2024-10-28 13:05:41,A,"12,900",387

문제 ​

  1. 적재 시간이 어디에 쓰이는지 세션 통계와 HPROF로 설명하고, 214줄이 오류로 빠진 이유를 쓰시오.
  2. 파일을 SQL로 읽는 외부 테이블과 직접 경로 적재로 다시 작성하시오. 잘못된 줄을 어떻게 남기고, 파일이 통째로 깨졌을 때는 어떻게 멈출지도 쓰시오.
  3. 고친 방법이 기대는 전제와 그 대가를 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자