Skip to content
튜닝 연습DML과 배치 튜닝
DML-048

판매 일보가 작년 상반기 날짜는 금방 뜨는데 하반기 날짜는 80배 블록을 읽는다

기초UPDATE유통473 / 700

상황 ​

본사 레거시 유통은 2023년 7월부터 판매를 ERP로 넘긴다. POS가 판매를 넣을 때 ERP_ST는 'N', ERP_MSG는 비어 있고, 매일 02:00 연동 배치가 ERP 응답을 받아 두 칸을 채운다. ERP_MSG에는 전표 번호와 승인 문구가 약 120바이트 들어간다. 1월 첫 주 MD팀: "「일별 판매 일보」가 작년 상반기 날짜는 금방 뜨는데 하반기 날짜는 느려요." 통계는 매일 DBMS_STATS로 모으고, USER_TABLES.CHAIN_CNT는 0이다.

테이블과 인덱스 ​

  • CF10 판매: 500,000행 · SLE_DT '20220101' ~ '20231231' · 하루 약 700건 · 날짜순으로 들어온다. 이 문제에서는 ERP_ST VARCHAR2(1)와 ERP_MSG VARCHAR2(200) 칸이 더 있고, 2023-07-01 이후 판매 128,640건에 두 칸이 채워졌다. PCTFREE는 기본값 10이다.
  • 행 길이는 연동 전 약 72바이트, ERP_MSG를 채운 뒤 약 192바이트다.
  • 인덱스: CF10_PK (SLE_NO) · IX_CF10_SLE_DT (SLE_DT)
  • USER_TABLES(어젯밤 DBMS_STATS): NUM_ROWS 500,000 · BLOCKS 6,214 · AVG_ROW_LEN 103 · CHAIN_CNT 0. 연동 칸이 없던 때의 판매는 4,583블록이었다.
  • ERP 응답은 ERP_RCV (SLE_NO, ERP_MSG)로 받는다. 일요일 03:00 ~ 06:00에는 POS 입력이 없다.

원본 SQL ​

sql
-- 매일 02:00 · ERP 연동 결과 반영
UPDATE CF10 s
   SET (s.ERP_ST, s.ERP_MSG) = (SELECT 'Y', r.ERP_MSG FROM ERP_RCV r WHERE r.SLE_NO = s.SLE_NO)
 WHERE s.ERP_ST = 'N'
   AND EXISTS (SELECT 1 FROM ERP_RCV r WHERE r.SLE_NO = s.SLE_NO);

-- 「일별 판매 일보」
SELECT SHP_NO, COUNT(*) AS SLE_CNT, COUNT(CASE WHEN ERP_ST = 'Y' THEN 1 END) AS ERP_CNT
  FROM CF10
 WHERE SLE_DT = :v_dt
 GROUP BY SHP_NO;

실행계획 학습용 예시 · 행 이전의 비율은 교재 05화 실측과 같은 모양 ​

xplan
[일별 판매 일보 — :v_dt = '20231115']
-------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                |      1 |        |      6 |00:00:00.02 |     846 |
|   1 |  HASH GROUP BY                       |                |      1 |      6 |      6 |00:00:00.02 |     846 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| CF10           |      1 |    700 |    698 |00:00:00.02 |     846 |
|*  3 |    INDEX RANGE SCAN                  | IX_CF10_SLE_DT |      1 |    700 |    698 |00:00:00.01 |       4 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("SLE_DT"=:V_DT)

[같은 SQL — :v_dt = '20230615']
  같은 계획 · A-Rows 702 · Buffers 11 (인덱스 4)

[V$MYSTAT 증가분 — 한 번 실행할 때]
  table fetch continued row     '20230615' → 0 · '20231115' → 421

[월 판매 집계 — 같은 테이블 전체 스캔]
  TABLE ACCESS FULL CF10 · Buffers 6,218 (연동 칸이 없던 때 4,583)

[시험 DB 사본 — ANALYZE TABLE CF10 LIST CHAINED ROWS INTO CHAINED_ROWS]
  77,912행 · 전부 SLE_DT >= '20230701'

문제 ​

  1. 같은 SQL이 2023년 6월 날짜는 11블록, 11월 날짜는 846블록을 읽는 이유를 설명하시오. CHAIN_CNT가 0인데도 그렇게 판단하는 근거를 쓰시오.
  2. 이미 생긴 문제를 고치고, 앞으로 다시 생기지 않도록 연동 배치를 고치시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자