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

야간 주문 파일 배치에 DETERMINISTIC을 붙였지만 함수 호출은 10만 번 그대로다

중급PLSQL한빛유통662 / 700

상황 ​

야간 배치 「지역별 주문 파일」은 주문 10만 건을 읽어 물류사에 보낼 파일을 한 줄씩 쓴다. 줄마다 고객의 지역명을 함수 FN_RGN_NM으로 붙인다. 지난주 개발자가 이 함수에 DETERMINISTIC을 붙였다. 고객은 2,000명뿐이니 같은 고객의 지역명은 한 번만 계산될 것이라고 봤다. 개발자가 SQL로 시험했을 때(SELECT COUNT(FN_RGN_NM(CUS_ID)) FROM T_ORD)는 함수 본문이 100,000번에서 57,671번으로 줄었다. 그런데 배치의 경과 시간은 1.6초 그대로이고, 함수 본문도 10만 번 그대로 돈다.

테이블과 인덱스 ​

  • T_ORD 주문: 100,000행 · 896블록 · 고객 2,000명이 돌아가며 섞여 있다(고객 한 명에 약 50건)
  • M_CUS 고객: 2,000행 · 30블록 · PK_M_CUS (CUS_ID) · RGN_ID
  • M_RGN 지역: 8행 · 4블록 · PK_M_RGN (RGN_ID)
  • 파일 쓰기(UTL_FILE)는 배치 시간 중 약 0.3초를 쓴다 · 주문의 고객은 모두 M_CUS에 있다 · 통계 최신

원본 SQL ​

sql
CREATE OR REPLACE FUNCTION FN_RGN_NM(p_cus_id VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS   -- 지난주 DETERMINISTIC 추가
  v_nm M_RGN.RGN_NM%TYPE;
BEGIN
  SELECT r.RGN_NM INTO v_nm
    FROM M_CUS c, M_RGN r
   WHERE c.CUS_ID = p_cus_id
     AND r.RGN_ID = c.RGN_ID;
  RETURN v_nm;
END;
/

PROCEDURE P_ORD_FILE(p_dir VARCHAR2) IS
  f     UTL_FILE.FILE_TYPE;
  v_rgn M_RGN.RGN_NM%TYPE;
BEGIN
  f := UTL_FILE.FOPEN(p_dir, 'ord_rgn.csv', 'w');
  FOR r IN (SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_AMT FROM T_ORD) LOOP
    v_rgn := FN_RGN_NM(r.CUS_ID);
    UTL_FILE.PUT_LINE(f, r.ORD_SEQ || ',' || r.CUS_ID || ',' || v_rgn || ',' ||
                         TO_CHAR(r.ORD_DT, 'YYYYMMDDHH24MISS') || ',' || r.ORD_AMT);
  END LOOP;
  UTL_FILE.FCLOSE(f);
END;

실행계획 학습용 예시 ​

xplan
[세션 통계: P_ORD_FILE 한 번]
  판                   경과      recursive calls   session logical reads   함수 본문 실행
  DETERMINISTIC 전     1.63 초          101,017                 501,913           100,000
  DETERMINISTIC 후     1.62 초          101,017                 501,911           100,000

[TKPROF 모양: 재귀 문장 둘]
  SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_AMT FROM T_ORD
     Execute 1 · Fetch 1,001 · rows 100,000 · query 1,897
  SELECT R.RGN_NM FROM M_CUS C, M_RGN R WHERE C.CUS_ID = :B1 AND R.RGN_ID = C.RGN_ID
     Execute 100,000 · Fetch 100,000 · rows 100,000 · query 500,000 (한 번에 5블록)

[개발자의 시험: SQL 한 문장 (한 번의 페치)]
  SELECT COUNT(FN_RGN_NM(CUS_ID)) FROM T_ORD    함수 본문 100,000 → 57,671

문제 ​

  1. SQL 시험에서는 줄었던 호출이 배치에서는 하나도 줄지 않은 이유를 설명하시오.
  2. 같은 파일을 쓰면서 함수 호출이 사라지도록 배치를 고치시오. 함수의 DETERMINISTIC은 어떻게 할지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자