테마
본사 회계팀의 「기간별 판매 전표」 화면은 시작일과 종료일을 달력에서 고르고, Java가 두 값을 DATE 바인드(setDate)로 넘긴다. 한 달을 고르면 1초 가까이 걸린다.
SLE_DT가 문자 컬럼이라서 개발자는 공통 함수 FN_STR2DT로 판매일을 날짜로 바꿔 비교했다. 개발자의 설명은 "형변환을 직접 했으니 묵시적 형변환 문제는 없다"는 것이다.
CF10 판매: 500,000행 · 4,583블록 · SLE_DT VARCHAR2(8) '20231201' · 2022 ~ 2023년 · 2023년 12월 20,864건IX_CF10_SLE_DT (SLE_DT): 이 문제에서는 있다 · 리프 1,393블록 · 통계 최신FN_STR2DT: SQL이 없는 PL/SQL 함수 · 날짜로 바꿀 수 없는 문자열이면 NULL을 돌려준다 · 다른 화면 10여 곳도 쓴다SLE_DT에는 날짜로 바꿀 수 없는 값이 없다CREATE OR REPLACE FUNCTION FN_STR2DT(p_ymd VARCHAR2) RETURN DATE IS
BEGIN
RETURN TO_DATE(p_ymd, 'YYYYMMDD');
EXCEPTION
WHEN OTHERS THEN RETURN NULL; -- 잘못된 날짜 문자열은 NULL
END;
/
-- :d_fr = 2023-12-01, :d_to = 2023-12-31 (DATE 바인드)
SELECT h.SLE_NO, h.SLE_DT, h.SLE_HMS, h.SHP_NO
FROM CF10 h
WHERE FN_STR2DT(h.SLE_DT) BETWEEN :d_fr AND :d_to;
[DISPLAY_CURSOR (ALLSTATS LAST) · 2023-12-01 ~ 2023-12-31]
-------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20864 |00:00:00.94 | 4583 |
|* 1 | TABLE ACCESS FULL | CF10 | 1 | 1250 | 20864 |00:00:00.94 | 4583 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("PUP"."FN_STR2DT"("H"."SLE_DT")>=:D_FR AND "PUP"."FN_STR2DT"("H"."SLE_DT")<=:D_TO))
[V$SQL: 이 문장] ELAPSED_TIME 0.94 초 · CPU_TIME 0.92 초 · PLSQL_EXEC_TIME 0.71 초 · BUFFER_GETS 4,583
[DBMS_HPROF: FN_STR2DT] 호출 520,864번 (함수 안에 SQL이 없어 recursive calls는 늘지 않는다)
SLE_DT에 인덱스가 있는데도 테이블 전체를 읽는 이유를 Predicate Information으로 설명하시오. 함수가 행 수(500,000)보다 많은 520,864번 호출된 이유도 쓰시오.