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

매장은 다섯 곳뿐인데 월간 판매 내려받기 한 번에 SQL이 2만 번 실행된다

기초SELECT유통655 / 700

상황 ​

본사 회계팀은 매달 초 「월간 판매 내려받기」로 지난달 판매 전표를 파일로 받는다. 매장명은 공통 함수 FN_SHP_NM이 붙이는데, 이 함수는 화면 40여 곳이 함께 쓰고 있어서 개발팀은 함수를 고치기를 꺼린다. DBA가 내려받기 한 번의 세션 통계를 보내왔다. "전표는 2만 건인데 recursive calls도 2만 번이다. 매장은 다섯 곳뿐인데."

테이블과 인덱스 ​

  • CF10 판매: 500,000행 · 4,583블록 · SLE_DT VARCHAR2(8) · 2023년 12월 20,864건 · 판매 매장은 5곳(SHP_NO 1001 ~ 1005)
  • 인덱스 IX_CF10_SLE_DT (SLE_DT): 이 문제에서는 있다 · 통계 최신
  • CF07 매장: 6행(본사 1000과 매장 5곳) · 4블록 · CF07_PK (SHP_NO)
  • 함수 안의 SELECT는 호출마다 따로 실행되는 재귀 SQL이다(dep=1).

원본 SQL ​

sql
CREATE OR REPLACE FUNCTION FN_SHP_NM(p_shp_no NUMBER) RETURN VARCHAR2 IS
  v_nm CF07.SHP_NM%TYPE;
BEGIN
  SELECT SHP_NM INTO v_nm FROM CF07 WHERE SHP_NO = p_shp_no;
  RETURN v_nm;
END;
/

SELECT h.SLE_NO, h.SLE_DT, h.SLE_HMS, h.SHP_NO,
       FN_SHP_NM(h.SHP_NO) AS shp_nm
  FROM CF10 h
 WHERE h.SLE_DT BETWEEN '20231201' AND '20231231';

실행계획 학습용 예시 ​

xplan
[DISPLAY_CURSOR (ALLSTATS LAST)]
------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                |      1 |        |  20864 |00:00:00.24 |     295 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| CF10           |      1 |  20833 |  20864 |00:00:00.02 |     295 |
|*  2 |   INDEX RANGE SCAN                  | IX_CF10_SLE_DT |      1 |  20833 |  20864 |00:00:00.01 |      98 |
------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("H"."SLE_DT">='20231201' AND "H"."SLE_DT"<='20231231')

[세션 통계: 내려받기 한 번 (V$MYSTAT 증가분)]
  경과 시간                 0.24 초
  recursive calls           20,871
  execute count             20,866
  session logical reads     42,023

[V$SQL: 함수 안의 문장 (dep=1)]
  SELECT SHP_NM FROM CF07 WHERE SHP_NO = :B1    EXECUTIONS 20,864 · ROWS 20,864 · BUFFER_GETS 41,728 (한 번에 2블록)

문제 ​

  1. 매장이 다섯 곳인데 recursive calls가 2만 번인 이유를 설명하시오. 그 일이 계획의 Buffers(295)에 보이지 않는 이유도 쓰시오.
  2. 함수는 고치지 않고 SQL만 고쳐 함수 호출을 매장 수만큼으로 줄이시오. 이 방법이 통하는 조건과 통하지 않는 경우도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자