테마
한빛유통 정산팀은 매달 말일 오후에 고객별 정산을 「전표 확정」 화면으로 확정한다. 담당자 열두 명이 두 시간 동안 약 1,800건을 확정한다. 회계 규정 제14조는 이렇다. "전표번호는 1번부터 결번 없이 이어져야 한다. 결번은 허용하지 않는다." 그래서 전표번호는 시퀀스가 아니라 채번 테이블로 매긴다. 혼자 테스트하면 확정 한 건은 0.12초인데, 월말 오후에는 한 건에 평균 1.9초가 걸린다. 오과장은 "서버가 바빠서 그렇다"라고 했다.
T_STLM_NUM 채번: PK (NUM_TP) · 이 문제에서는 전표번호 행 NUM_TP = 'SLIP'을 쓴다T_ORD_STLM 정산: 100,000행 · 640블록 · 이 문제에서는 전표번호 컬럼 SLIP_NO를 더했다 · 인덱스 IX_T_ORD_STLM_CUS (CUS_ID, STLM_DT)T_STLM_SLIP 전표(이 문제를 위해 더한 테이블): 한 달 약 1,800행 · PK (SLIP_NO)T_ORD_BIG: 1,000,000행 · 5,826블록 · 확정할 때 주문 원장과 금액을 대어 본다 · CUS_ID로 찾는 인덱스는 없다 · 고객 한 명의 한 달 주문은 약 14건PROCEDURE CONFIRM_SLIP(p_cus_id VARCHAR2, p_ym VARCHAR2) IS
v_no NUMBER;
v_amt NUMBER;
v_from DATE := TO_DATE(p_ym, 'YYYYMM');
BEGIN
-- ① 전표번호부터 받는다
SELECT LAST_NO + 1 INTO v_no FROM T_STLM_NUM WHERE NUM_TP = 'SLIP' FOR UPDATE;
UPDATE T_STLM_NUM SET LAST_NO = v_no WHERE NUM_TP = 'SLIP';
-- ② 주문 원장과 금액을 대어 본다
SELECT SUM(ORD_AMT) INTO v_amt
FROM T_ORD_BIG
WHERE CUS_ID = p_cus_id
AND ORD_DT >= v_from AND ORD_DT < ADD_MONTHS(v_from, 1);
-- ③ 정산 행에 전표번호를 적고 전표를 만든다
UPDATE T_ORD_STLM SET SLIP_NO = v_no
WHERE CUS_ID = p_cus_id AND STLM_DT >= v_from AND STLM_DT < ADD_MONTHS(v_from, 1);
INSERT INTO T_STLM_SLIP (SLIP_NO, CUS_ID, SLIP_YM, SLIP_AMT, REG_DT)
VALUES (v_no, p_cus_id, p_ym, v_amt, SYSDATE);
COMMIT;
END;
[혼자 한 건 — 단계별 경과]
① 번호 받기 0.001초 · Buffers 5 (INDEX UNIQUE SCAN)
② 원장 대조 0.11초 · Buffers 5,826 (TABLE ACCESS FULL T_ORD_BIG)
③ 전표 쓰기 0.004초 · Buffers 12
COMMIT 0.003초
① 에서 COMMIT 까지 채번 행을 쥐는 시간 약 0.12초
[② 원장 대조 — ALLSTATS LAST]
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.11 | 5826 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.11 | 5826 |
|* 2 | TABLE ACCESS FULL| T_ORD_BIG | 1 | 14 | 14 |00:00:00.11 | 5826 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("CUS_ID"=:B3 AND "ORD_DT">=:B2 AND "ORD_DT"<ADD_MONTHS(:B2,1)))
[월말 오후 — 열두 명 · 14:00 ~ 16:00]
확정 1,804건 · 한 건 평균 1.9초 (그중 기다림 1.6초)
enq: TX - row lock contention 1,690번 · 평균 1.7초 · 대상 T_STLM_NUM ('SLIP' 행)
[V$SESSION — 14:37:12]
SID EVENT SECS BLOCKING_SESSION 하는 문장
121 db file scattered read 0 SELECT SUM(ORD_AMT) … T_ORD_BIG …
140 enq: TX - row lock contention 1 121 SELECT LAST_NO + 1 … FOR UPDATE
152 enq: TX - row lock contention 1 121 SELECT LAST_NO + 1 … FOR UPDATE
… (아홉 명 더 · 모두 BLOCKING_SESSION 121)