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

월 감사 출력이 판매번호를 1,000개씩 나눠 스물한 번 보내고 8만 블록을 읽는다

중급SELECT유통147 / 700

상황 ​

본사 감사팀은 매달 초 지난달 판매상품 원장을 출력한다. 출력 프로그램은 먼저 CF10에서 지난달 판매번호 목록을 받고, 그 번호를 1,000개씩 묶어 CF11에 IN 목록으로 보낸다. 2023년 12월은 판매가 20,864건이라 스물한 번 보냈다. 개발자는 이렇게 설명했다. "IN에는 1,000개까지만 넣을 수 있어서(ORA-01795) 나눴다. PK로 한 건씩 정확히 찾으니 가장 빠르다." 그런데 출력에 1분이 넘게 걸리고, 그동안 매장 POS의 판매 등록이 느려진다는 말이 나온다.

테이블과 인덱스 ​

  • CF11 판매상품: 1,096,708행 · 8,204블록(블록당 약 134행) · 판매번호 순으로 쌓였다 · SLE_NO는 'YYYYMMDD-NNNN'(앞 8자리가 판매일) · 영수증 한 장에 평균 2.2줄 · 2023년 12월 46,322줄
  • CF11_PK (SLE_NO, ITM_NO): BLEVEL 2 · 리프 약 4,290블록(리프 한 블록에 약 256항목) · CLUSTERING_FACTOR 16,735 · 통계 최신
  • CF10 판매: 2023년 12월 20,864건 · CF10_PK (SLE_NO)

원본 SQL ​

sql
-- 출력 프로그램 · 판매번호 1,000개씩 (2023년 12월은 21번)
SELECT SUBSTR(SLE_NO, 1, 8) AS sle_dt, SLE_NO, ITM_NO, SLE_QTY, SLE_UPRC,
       SLE_QTY * SLE_UPRC AS sle_amt
  FROM CF11
 WHERE SLE_NO IN (:b1, :b2, :b3, /* … */ :b1000)
 ORDER BY SLE_NO, ITM_NO

실행계획 학습용 예시 · 건수와 인덱스 규모는 적재 데이터(CF10 · CF11) 그대로 ​

xplan
[한 번 · 판매번호 1,000개 · 2,212줄]
--------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |      1 |        |   2212 |00:00:02.91 |    4058 |  1203 |
|   1 |  INLIST ITERATOR             |         |      1 |        |   2212 |00:00:02.91 |    4058 |  1203 |
|   2 |   TABLE ACCESS BY INDEX ROWID| CF11    |   1000 |   2200 |   2212 |00:00:02.88 |    4058 |  1203 |
|*  3 |    INDEX RANGE SCAN          | CF11_PK |   1000 |   2200 |   2212 |00:00:00.41 |    3012 |   188 |
--------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access(("SLE_NO"=:B1 OR "SLE_NO"=:B2 OR … OR "SLE_NO"=:B1000))

[2023년 12월 · 스물한 번 합계]  Buffers 약 85,000 · Reads 약 25,000 · 경과 1분 3초

문제 ​

  1. 한 번(판매번호 1,000개)에 약 4,000블록, 한 달 스물한 번에 약 8만 5천 블록이 되는 이유를 인덱스 높이와 키 수로 어림해 설명하시오.
  2. 같은 결과를 내도록 SQL을 고치고, 고친 SQL이 읽을 블록 수를 리프 블록 수와 CLUSTERING_FACTOR로 어림하시오.
  3. IN 목록으로 키를 하나씩 찾는 편이 나은 경우를 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자