테마
주문관리팀의 「최근 영업일 결제 대기」 화면은 최근 n영업일 동안 들어온 결제 대기 주문을 보여 준다. 담당자들이 하루 300번쯤 열고, 한 번에 0.9초가 걸린다. 지난주 이 화면을 위해 (ORD_ST, ORD_DT) 인덱스를 만들었지만 계획은 그대로다.
기준일은 회사 공통 함수 FN_BIZ_DAY_FROM이 영업일 달력을 읽어 구한다. 개발자는 "함수는 오른쪽 값에만 썼고 컬럼은 가공하지 않았다"라고 한다.
T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT DATE(전부 자정, 2022-01-01 ~ 2024-12-31, 하루 약 912건) · ORD_ST PENDING 8%(80,000행)IX_ORD_BIG_ST_DT (ORD_ST, ORD_DT): 지난주 생성 · 리프 2,950블록 · 통계 최신(히스토그램 없음)T_BIZ_CAL 영업일 달력(이 문제에서 쓰는 테이블): 1,096행 · 5블록 · CAL_DT DATE · BIZ_YN · PK (CAL_DT) · 함수 안 SQL은 호출마다 3블록CREATE OR REPLACE FUNCTION FN_BIZ_DAY_FROM(p_days NUMBER) RETURN DATE IS
v_dt DATE;
BEGIN
SELECT MIN(CAL_DT) INTO v_dt
FROM (SELECT CAL_DT
FROM T_BIZ_CAL
WHERE CAL_DT <= TRUNC(SYSDATE)
AND BIZ_YN = 'Y'
ORDER BY CAL_DT DESC)
WHERE ROWNUM <= p_days;
RETURN v_dt;
END;
/
-- :days = 3
SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_AMT
FROM T_ORD_BIG
WHERE ORD_ST = 'PENDING'
AND ORD_DT >= FN_BIZ_DAY_FROM(:days)
ORDER BY ORD_DT DESC, ORD_SEQ DESC;
[DISPLAY_CURSOR (ALLSTATS LAST) · :days = 3]
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 367 |00:00:00.91 | 5826 | |
| 1 | SORT ORDER BY | | 1 | 4000 | 367 |00:00:00.91 | 5826 | 38912 (0)|
|* 2 | TABLE ACCESS FULL| T_ORD_BIG | 1 | 4000 | 367 |00:00:00.91 | 5826 | |
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("ORD_ST"='PENDING' AND "ORD_DT">="FN_BIZ_DAY_FROM"(:DAYS)))
[세션 통계: 화면 한 번] recursive calls 80,012 · session logical reads 245,861
[V$SQL: 함수 안 문장 (dep=1) · 화면 한 번의 증가분]
SELECT MIN(CAL_DT) FROM (SELECT CAL_DT FROM T_BIZ_CAL WHERE CAL_DT <= TRUNC(SYSDATE) …) WHERE ROWNUM <= :B1
EXECUTIONS 80,000 · BUFFER_GETS 240,000 (한 번에 3블록)
E-Rows와 Predicate Information으로 설명하시오.FN_BIZ_DAY_FROM)은 그대로 쓰면서 인덱스 범위 스캔이 되도록 고치시오. 함수를 스칼라 서브쿼리로 감싸는 안과 견주어 쓰시오.