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

월초 주문 스냅샷 10만 건이 같은 10만 건을 넣는 정산 적재보다 아홉 배 느리다

중급DDL한빛유통694 / 700

상황 ​

한빛유통은 매월 1일 02:00에 주문 10만 건의 상태를 주문 이력 T_ORD_HIS에 스냅샷으로 남긴다. 이력 번호(HIS_SEQ)는 2016년에 만든 트리거 TRG_ORD_HIS_BI가 시퀀스로 채운다. 고객센터의 주문 상태 변경 화면도 T_ORD_HIS에 한 줄씩 넣는데, 이 화면은 HIS_SEQ 자리에 NULL을 넣는다(트리거가 채운다는 전제다). 스냅샷이 3.6초 걸린다. 오과장이 물었다. "같은 T_ORD 10만 건을 넣는 P1 적재는 0.4초인데 왜 아홉 배죠?"

테이블과 인덱스 ​

  • T_ORD: 100,000행 · 896블록
  • T_ORD_HIS 주문 이력(이 문제용): HIS_SEQ NUMBER NOT NULL · ORD_SEQ · ORD_ST · HIS_DT · HIS_TP('SNAP' 월초 스냅샷, 'CHG' 상태 변경) · PK_T_ORD_HIS (HIS_SEQ) · 지금 2,412,000행
  • 시퀀스 SQ_ORD_HIS: CACHE 20(기본값) · 이력 번호는 겹치지만 않으면 되고, 결번은 상관없다
  • 고객센터 화면: INSERT INTO T_ORD_HIS VALUES (NULL, :ord_seq, :st, SYSDATE, 'CHG') · 하루 약 600번 · 화면 소스는 이번에 고치지 않는다
  • 운영 DB는 19c다.

원본 SQL ​

sql
-- 2016년 트리거 — 이력 번호를 시퀀스로 채운다
CREATE OR REPLACE TRIGGER TRG_ORD_HIS_BI
BEFORE INSERT ON T_ORD_HIS
FOR EACH ROW
BEGIN
  SELECT SQ_ORD_HIS.NEXTVAL INTO :NEW.HIS_SEQ FROM dual;
END;
/

-- 월초 주문 스냅샷 (매월 1일 02:00)
INSERT INTO T_ORD_HIS (ORD_SEQ, ORD_ST, HIS_DT, HIS_TP)
SELECT ORD_SEQ, ORD_ST, TRUNC(SYSDATE), 'SNAP'
  FROM T_ORD;
COMMIT;

실행계획 학습용 예시 ​

xplan
[세션 통계 — 월초 스냅샷 10만 건]
  경과 시간 3.62 초 · CPU 3.31 초
  recursive calls          105,061
  execute count            105,014
  session logical reads    341,207
  redo size                38.9 MB

[TKPROF]
INSERT INTO T_ORD_HIS (ORD_SEQ, ORD_ST, HIS_DT, HIS_TP) SELECT ORD_SEQ, ORD_ST, TRUNC(SYSDATE), 'SNAP' FROM T_ORD   (dep=0)

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Execute      1      0.95       1.02          0        904     314377      100000

SELECT SQ_ORD_HIS.NEXTVAL FROM DUAL                                    (dep=1 · 트리거 안)

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Execute 100000      1.44       1.52          0          0          0           0
Fetch   100000      0.38       0.41          0          0          0      100000

update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#=:5,order$=:6,cache=:7,highwater=:8,... where obj#=:1   (dep=2)

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Execute   5000      0.22       0.24          0       5000      10213        5000

[비교 — P1 적재 (T_ORD → T_ORD_STLM · 트리거 없음)]  경과 0.41 초 · recursive calls 31

문제 ​

  1. 같은 10만 건인데 스냅샷만 아홉 배 느린 이유를 TKPROF의 세 문장으로 설명하시오.
  2. 이력 번호의 번호원(시퀀스 하나)과 고객센터 화면을 그대로 두고, 스냅샷이 행마다 번호를 받으러 가지 않도록 고치시오. 화면이 HIS_SEQ에 NULL을 넣는다는 점을 어떻게 처리했는지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자