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

같은 집계에 FULL 힌트를 주자 다른 숫자가 나왔다

중급DDL유통653 / 700

상황 ​

본사 유통지원팀의 「대분류별 판매 수량」 리포트는 함수 FN_TOP_CTG로 상품의 대분류를 구한다. 2년 전 개발자가 이렇게 짰고, 느리다는 말이 나오자 그 함수로 인덱스도 만들었다. 소스 주석에는 이렇게 적혀 있다. "ORA-30553이 나서 DETERMINISTIC을 붙였더니 됐다." 어제 상품 분류 개편으로 아이스크림(중분류 114)을 음료(100)에서 푸드(200) 아래로 옮겼다(CF02 한 줄을 고치고 커밋). 오늘 회계팀에서 연락이 왔다. "푸드 판매 수량이 판매 원장과 안 맞는다." 확인하려고 같은 문장에 FULL 힌트를 주자 다른 숫자가 나왔다.

테이블과 인덱스 ​

  • CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · 함수 기반 인덱스 CF11_FX01 (FN_TOP_CTG(ITM_NO), SLE_QTY)(리프 약 2,440블록)
  • CF01 상품: 109행 · 5블록 · PK(ITM_NO) · CTG_NO(중분류)
  • CF02 카테고리: 18행 · 4블록 · PK(CTG_NO) · UP_CTG_NO(대분류 100 음료 · 200 푸드 · 300 굿즈 · 900 기타)
  • 판매된 상품 88종 · 푸드(브레드, 케이크, 샌드위치) 21종 105,736행 · 아이스크림 3종 9,350행(수량 23,434)

원본 SQL ​

sql
CREATE OR REPLACE FUNCTION FN_TOP_CTG(p_itm_no NUMBER) RETURN NUMBER DETERMINISTIC IS
  v_up NUMBER;
BEGIN
  SELECT c.UP_CTG_NO INTO v_up
    FROM CF01 i, CF02 c
   WHERE i.ITM_NO = p_itm_no
     AND c.CTG_NO = i.CTG_NO;
  RETURN v_up;
END;
/

CREATE INDEX CF11_FX01 ON CF11 (FN_TOP_CTG(ITM_NO), SLE_QTY);

-- 대분류별 판매 수량 (:top = 200 푸드)
SELECT SUM(SLE_QTY) AS qty, COUNT(*) AS lines
  FROM CF11
 WHERE FN_TOP_CTG(ITM_NO) = :top;

실행계획 학습용 예시 · 건수와 수량은 원본 데이터로 셈 ​

xplan
[어제 — 분류 개편]
 UPDATE CF02 SET UP_CTG_NO = 200 WHERE CTG_NO = 114;   COMMIT;

[오늘 — 그대로 돌림 (:top = 200)]
-----------------------------------------------------------------------------------------
| Id  | Operation         | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |      1 |        |      1 |00:00:00.02 |     237 |
|   1 |  SORT AGGREGATE   |           |      1 |      1 |      1 |00:00:00.02 |     237 |
|*  2 |   INDEX RANGE SCAN| CF11_FX01 |      1 |    366K|    105K|00:00:00.01 |     237 |
-----------------------------------------------------------------------------------------
   2 - access("PUP"."FN_TOP_CTG"("ITM_NO")=:TOP)

      QTY      LINES
  264,496    105,736

[확인 — 같은 문장에 /*+ FULL(CF11) */]
-----------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      1 |00:00:00.48 |    8204 |
|   1 |  SORT AGGREGATE    |      |      1 |      1 |      1 |00:00:00.48 |    8204 |
|*  2 |   TABLE ACCESS FULL| CF11 |      1 |    366K|    115K|00:00:00.47 |    8204 |
-----------------------------------------------------------------------------------------
   2 - filter("PUP"."FN_TOP_CTG"("ITM_NO")=:TOP)
   (+ 함수 안 SQL — DETERMINISTIC 이라 한 번의 페치 안에서 같은 상품의 답을 기억한다)

      QTY      LINES
  287,930    115,086

문제 ​

  1. 같은 문장이 계획에 따라 다른 답을 내는 이유를 설명하고, 어느 쪽이 맞는지 쓰시오.
  2. 정합성과 속도를 둘 다 지키도록 DDL과 SQL을 고치시오.
  3. DETERMINISTIC을 붙여도 되는 함수의 조건을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자