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

채번 함수를 바꾼 뒤 정산 보정 적재가 0.3초에서 61초로 늘었다

실전PLSQL한빛유통504 / 700

상황 ​

12화의 장애 뒤에 한빛유통 개발팀은 채번 테이블을 그대로 두고, 번호 받기만 자율 트랜잭션 함수 FN_NEXT_NO로 떼어 냈다. 정산 등록 화면은 더 이상 10분씩 기다리지 않는다. 그런데 분기마다 지난 분기 주문 10만 건을 정산으로 다시 적재하는 보정 적재도 이 함수를 쓰도록 바꾸자, 적재가 0.3초에서 61초로 늘었다. 적재가 도는 동안에는 새벽 정산 보정 화면의 번호 받기도 들쭉날쭉 느려진다. 박팀장의 주문이다. "고치는 방법을 둘 이상 비교해서 고르고, 정산번호 규칙과 함께 대가를 적어 와라."

테이블과 인덱스 ​

  • T_ORD 주문: 100,000행 · 896블록 · 적재 원천(전부 옮긴다) · 적재는 주문이 들어오지 않는 새벽에 돈다
  • T_ORD_STLM 정산: 적재 대상 · PK_T_ORD_STLM (STLM_SEQ)
  • 정산번호 규칙(교재 12화에서 정한 그대로): 겹치면 안 되고, 결번은 사유를 기록하면 된다
  • T_STLM_NUM 채번: NUM_TP = 'STLM' 행 하나 · 지금 LAST_NO 412,000
  • 정산 보정 화면은 적재가 도는 새벽에도 하루 수십 번 FN_NEXT_NO('STLM')를 부른다

원본 SQL ​

sql
-- 12화 뒤에 만든 채번 함수 — 부른 쪽의 트랜잭션과 따로 COMMIT 한다
CREATE OR REPLACE FUNCTION FN_NEXT_NO(p_tp VARCHAR2) RETURN NUMBER IS
  PRAGMA AUTONOMOUS_TRANSACTION;
  v_no NUMBER;
BEGIN
  SELECT LAST_NO + 1 INTO v_no FROM T_STLM_NUM WHERE NUM_TP = p_tp FOR UPDATE;
  UPDATE T_STLM_NUM SET LAST_NO = v_no WHERE NUM_TP = p_tp;
  COMMIT;
  RETURN v_no;
END;

-- 정산 보정 적재 — 행마다 번호
INSERT INTO T_ORD_STLM (STLM_SEQ, ORD_SEQ, CUS_ID, STLM_DT, STLM_AMT)
SELECT FN_NEXT_NO('STLM'), ORD_SEQ, CUS_ID, ORD_DT, ORD_AMT
  FROM T_ORD;
COMMIT;

실행계획 학습용 예시 ​

xplan
[적재 INSERT — ALLSTATS LAST]
------------------------------------------------------------------------------------------------
| Id  | Operation                | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT         |            |      1 |        |      0 |00:01:01.20 |    211K |
|   1 |  LOAD TABLE CONVENTIONAL | T_ORD_STLM |      1 |        |      0 |00:01:01.20 |    211K |
|   2 |   TABLE ACCESS FULL      | T_ORD      |      1 |   100K |   100K |00:00:00.04 |     896 |
------------------------------------------------------------------------------------------------

[TKPROF — 적재 한 번에 함께 돈 재귀 SQL (FN_NEXT_NO 안)]
SQL                                                       Execute       Rows    current
SELECT LAST_NO + 1 FROM T_STLM_NUM WHERE … FOR UPDATE     100,000    100,000    100,000
UPDATE T_STLM_NUM SET LAST_NO = :B2 WHERE …               100,000    100,000    100,000
COMMIT (자율 트랜잭션)                                     100,000

[세션 통계 — 적재 한 번]
  경과 시간          61.2초   (번호 없이 같은 INSERT … SELECT 를 돌리면 0.3초)
  user commits       100,001
  recursive calls    약 400,000
  redo size          58.4MB

[새벽 보정 화면 — 적재가 도는 1분 동안]
  FN_NEXT_NO 한 번   평소 0.002초 → 0.02 ~ 0.4초 · enq: TX - row lock contention 37번

문제 ​

  1. 실행계획과 재귀 SQL, 세션 통계를 근거로 61초가 어디서 나오는지 설명하시오. 적재가 도는 동안 보정 화면의 번호 받기가 느려지는 이유도 쓰시오.
  2. 고치는 방법을 둘 이상 비교하고 하나를 골라 SQL로 작성하시오. 방법마다 결번이 언제 생기는지와 화면과의 경합이 어떻게 되는지도 함께 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자