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

연간 재료 소요 분석에서 92행짜리 상품 테이블 조회가 123만 번 실행된다

기초PLSQL버거667 / 700

상황 ​

버거 본사 구매팀은 연초마다 「연간 재료 소요 분석」을 돌려 매장 발주 기준을 정한다. 세트 메뉴는 버거, 사이드, 음료로 나눠 세야 해서 개발팀이 PL/SQL로 짰다. 나누는 규칙은 메뉴팀이 관리하는 패키지 PKG_SET_BOM에 있다. 2013년분을 돌리자 5.9초가 걸렸다. 구매팀 담당자가 물었다. "상품이 92개뿐인데 왜 6초나 걸리죠?" 조민우가 TKPROF를 떠 왔다.

테이블과 인덱스 ​

  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · 2013년분 1,236,358행 · ORD_DT VARCHAR2(8) · 인덱스 ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS)
  • ITEM 상품: 92행 · 5블록 · ITEM_PK (ITEM_ID) · ITEM_TYPE_CD는 100100 버거 · 100101 세트(17종) · 100102 치킨 · 100103 사이드 · 100104 디저트 · 100105 음료
  • 주문상품의 ITEM_ID는 모두 ITEM에 있다(FK는 없지만 적재 프로그램이 확인한다). 통계는 최신이다.
  • PKG_SET_BOM.ADD_QTY(item_id, type_cd, qty): SQL 없이 패키지 배열에 수량을 더하기만 한다(세트면 구성품마다 같은 수량을 더한다). SAVE는 상품별 소요량 92행을 넣는다.

원본 SQL ​

sql
PROCEDURE CALC_ITEM_NEED(p_yyyy VARCHAR2) IS          -- p_yyyy = '2013'
  v_tp  ITEM.ITEM_TYPE_CD%TYPE;
BEGIN
  PKG_SET_BOM.RESET;
  FOR r IN (SELECT ITEM_ID, ORD_ITEM_QTY
              FROM ORD_ITEM
             WHERE ORD_DT BETWEEN p_yyyy || '0101' AND p_yyyy || '1231') LOOP
    SELECT ITEM_TYPE_CD INTO v_tp
      FROM ITEM
     WHERE ITEM_ID = r.ITEM_ID;                           -- 주문상품 한 줄마다
    PKG_SET_BOM.ADD_QTY(r.ITEM_ID, v_tp, r.ORD_ITEM_QTY);  -- 세트면 구성품으로 나눠 더한다
  END LOOP;
  PKG_SET_BOM.SAVE(p_yyyy);
  COMMIT;
END;

실행계획 학습용 예시 ​

xplan
[세션 통계 — CALC_ITEM_NEED('2013') 한 번]
  경과 시간                  5.86 ~ 5.94 초
  recursive calls            1,248,745
  execute count              1,236,381
  session logical reads      2,540,438

[TKPROF — 문장별 (sys=no)]
SELECT ITEM_ID, ORD_ITEM_QTY FROM ORD_ITEM WHERE ORD_DT BETWEEN :B2 || '0101' AND :B1 || '1231'

call     count       cpu    elapsed       disk      query    current        rows
------- -------  -------- ---------- ---------- ---------- ----------  ----------
Parse         1      0.00       0.00          0          0          0           0
Execute       1      0.00       0.00          0          0          0           0
Fetch     12364      0.58       0.61          0      67629          0     1236358

Rows (1st)  Row Source Operation
   1236358  TABLE ACCESS FULL ORD_ITEM (cr=67629 pr=0 pw=0)

SELECT ITEM_TYPE_CD FROM ITEM WHERE ITEM_ID = :B1

call     count       cpu    elapsed       disk      query    current        rows
------- -------  -------- ---------- ---------- ---------- ----------  ----------
Parse         1      0.00       0.00          0          0          0           0
Execute 1236358      2.94       3.02          0          0          0           0
Fetch   1236358      1.71       1.76          0    2472716          0     1236358

Rows (1st)  Row Source Operation
         1  TABLE ACCESS BY INDEX ROWID ITEM (cr=2 pr=0 pw=0)
         1   INDEX UNIQUE SCAN ITEM_PK (cr=1 pr=0 pw=0)

문제 ​

  1. 5.9초가 어디서 나오는지 TKPROF의 두 문장으로 설명하시오. 구동 커서는 100건씩 묶여 있는데 상품 조회는 왜 묶이지 않았는지도 쓰시오.
  2. 소요량 결과가 바뀌지 않게 프로시저를 고치고, 고친 뒤의 일량을 숫자로 적으시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자