테마
한빛유통은 매일 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: 넣지 못한 줄과 오류 메시지를 남기는 테이블T_PG_STLM은 LOGGING이다. 01:30 ~ 02:30에는 이 테이블을 쓰는 다른 세션이 없다.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;
[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