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

작년까지 돌던 매장 수수료 재계산이 어젯밤 ORA-04036으로 죽었다

중급PLSQL버거670 / 700

상황 ​

버거 본사는 분기마다 전체 주문을 다시 읽어 매장별 주문 수수료를 다시 계산한다. 가맹 계약의 시간대별 요율 규칙은 PL/SQL 패키지 PKG_SHOP_FEE에 있다. 2012년분만 있던 첫해에는 문제없이 돌았다. 어젯밤 01:12, 정산 배치 두 개와 시간이 겹치자 이 배치가 ORA-04036으로 죽었다. DBA의 말은 이렇다. "이 세션 하나가 PGA를 1.1GB 넘게 잡고 있었어요. 같은 시각 정산 배치의 해시 조인은 TEMP로 넘쳤고요."

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_NO NUMBER(10) · ORD_DT VARCHAR2(8) · ORD_HMS VARCHAR2(6) · SHOP_NO VARCHAR2(10) · 채움 컬럼 UPPER2 · UPPER_CASE · LOWER_CASE · ALPHABET VARCHAR2(400) · ALPHABET_NUMERIC VARCHAR2(400)
  • PKG_SHOP_FEE.ADD_ORD(shop_no, ord_dt, ord_hms): SQL 없이 매장, 월별 수수료를 패키지 배열에 더한다 · FLUSH가 매장, 월별 4,800행을 넣는다
  • 인스턴스: PGA_AGGREGATE_TARGET 1GB · PGA_AGGREGATE_LIMIT 2GB

원본 SQL ​

sql
PROCEDURE RECALC_SHOP_FEE IS
  TYPE t_ord IS TABLE OF ORD%ROWTYPE;
  v_ord t_ord;
BEGIN
  SELECT * BULK COLLECT INTO v_ord FROM ORD;            -- 100만 건을 한 번에
  FOR i IN 1 .. v_ord.COUNT LOOP
    PKG_SHOP_FEE.ADD_ORD(v_ord(i).SHOP_NO, v_ord(i).ORD_DT, v_ord(i).ORD_HMS);
  END LOOP;
  PKG_SHOP_FEE.FLUSH;
  COMMIT;
END;

실행계획 학습용 예시 ​

xplan
[세션 통계 — 지난 분기 (혼자 돈 날)]
  경과 시간                     4.6 초
  session pga memory max        1,183 MB
  session logical reads         22,431
  recursive calls               27

[어젯밤 01:12 — 정산 배치 두 개와 겹친 날]
  ORA-04036: PGA memory used by the instance exceeds PGA_AGGREGATE_LIMIT
  그 시각 인스턴스 PGA 할당량 약 2,050 MB (이 세션 1,183 MB)
  같은 시각 정산 배치의 HASH JOIN: Used-Tmp 312M (one-pass)

[2012년분만 있던 첫해 — 같은 프로그램]
  주문 500,124건 · session pga memory max 592 MB · 경과 2.3 초

문제 ​

  1. 이 세션 하나가 PGA를 1.1GB 넘게 잡은 이유와, 첫해에는 돌던 배치가 올해 죽은 이유를 설명하시오.
  2. 수수료 결과가 바뀌지 않게 배치를 고치시오. 루프를 빠져나가는 조건을 어디에 어떻게 두었는지와 LIMIT 값을 고른 근거도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자