Skip to content
튜닝 연습인덱스 스캔 효율과 테이블 액세스
ACC-034

한 달씩 나눠야 인덱스를 탄다던 월별 매장 집계 배치가 판매 테이블 크기의 두 배 반을 읽는다

중급PLSQL유통109 / 700

상황 ​

매일 밤 「월별 매장 판매 집계」 테이블을 2년 치 모두 다시 만든다. 반품 정정이 지난 달로 거슬러 올라가 들어오는 일이 있어서다. 대시보드와 월간 보고서가 이 집계 테이블을 읽는다. 배치 소스에는 개발자의 메모가 있다. "2년을 한 번에 읽으면 FULL이 된다. 한 달씩 24번 나눠 읽어 인덱스를 태운다." 배치 로그를 보면 한 달에 약 480블록씩, 24번이다. 오과장은 "한 번은 싸 보이는데 합치면 얼마냐"고 묻는다.

테이블과 인덱스 ​

  • CF10 판매: 500,000행 · 4,583블록 · 판매 날짜순으로 쌓였다 · 2022-01-01 ~ 2023-12-31(24개월) · 한 달 약 20,800건(4.2%) · 매장 다섯 곳
  • 인덱스 IX_CF10_SLE_DT (SLE_DT): BLEVEL 2 · 리프 1,393 · CLUSTERING_FACTOR 9,921(교재 03화 실측) · 통계 최신
  • 집계 테이블 CF10_MON_SHP (YM, SHP_NO, SLE_CNT): 이 배치가 만드는 120행(24개월 × 5매장) · 인덱스 없음

원본 SQL ​

sql
DECLARE
  v_ym VARCHAR2(6);
BEGIN
  DELETE FROM CF10_MON_SHP;
  FOR m IN 0 .. 23 LOOP
    v_ym := TO_CHAR(ADD_MONTHS(DATE '2022-01-01', m), 'YYYYMM');
    INSERT INTO CF10_MON_SHP (YM, SHP_NO, SLE_CNT)
    SELECT v_ym, SHP_NO, COUNT(*)
      FROM CF10
     WHERE SLE_DT BETWEEN v_ym || '01' AND v_ym || '31'
     GROUP BY SHP_NO;
  END LOOP;
  COMMIT;
END;

실행계획 학습용 예시 · 건수는 적재 데이터(CF10) 그대로 ​

xplan
[루프 한 번 · 2023년 12월 (20,864건)]
------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT                      |                |      1 |        |      0 |00:00:00.01 |     483 |
|   1 |  LOAD TABLE CONVENTIONAL              | CF10_MON_SHP   |      1 |        |      0 |00:00:00.01 |     483 |
|   2 |   HASH GROUP BY                       |                |      1 |      5 |      5 |00:00:00.01 |     479 |
|   3 |    TABLE ACCESS BY INDEX ROWID BATCHED| CF10           |      1 |   1250 |  20864 |00:00:00.01 |     479 |
|*  4 |     INDEX RANGE SCAN                  | IX_CF10_SLE_DT |      1 |   1250 |  20864 |00:00:00.01 |      60 |
------------------------------------------------------------------------------------------------------------------
   4 - access("SLE_DT">=:B1||'01' AND "SLE_DT"<=:B1||'31')

[TKPROF · 배치 한 번]
INSERT INTO CF10_MON_SHP (YM, SHP_NO, SLE_CNT) SELECT :B1 , SHP_NO, COUNT(*) FROM CF10 ...
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute     24      0.12       0.13          0      11362         96         120
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       25      0.12       0.13          0      11362         96         120

[같은 집계를 한 문장으로 · FULL]  CF10 4,583블록 한 번

문제 ​

  1. 한 번에 약 480블록인 루프가 24번 합쳐 11,362블록이 되는 이유를 IX_CF10_SLE_DT의 리프와 CLUSTERING_FACTOR로 설명하시오. 그 합이 테이블 전체 블록 4,583보다 큰 이유도 설명하시오.
  2. 같은 결과를 내도록 배치를 고치시오. 한 달씩 인덱스로 읽는 편이 맞는 경우가 있다면 어떤 경우인지도 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자