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

메뉴별 월 추이를 빠르게 하려고 판매상품 테이블을 메뉴 순으로 다시 쌓자는 제안서가 올라왔다

실전DDL유통107 / 700

상황 ​

MD팀의 「메뉴 월별 판매 추이」는 메뉴 하나의 2년 치 수량과 금액을 월별로 그린다. MD 여섯 명이 하루 수백 번 연다. 콜드브루(1010)를 고르면 7천 블록을 읽는다. 조민우의 제안서는 이렇다. "교재 04화에서 배운 대로 CF11을 (ITM_NO, SLE_NO) 순으로 정렬해 다시 쌓으면 CF가 좋아져 144블록이면 된다. 복사본으로 재 봤다. 점검 시간 30분이면 끝난다." 오과장은 이렇게 답했다. "CF11은 매장 POS의 영수증 재출력과 매장 마감도 쓴다. 다른 화면에 무슨 일이 생기는지까지 숫자로 보자."

테이블과 인덱스 ​

  • CF11 판매상품: 1,096,708행 · 8,204블록(블록당 약 134행) · 판매번호(SLE_NO 'YYYYMMDD-NNNN') 순으로 쌓였다 · 영수증 한 장에 평균 2.2줄 · POS가 매일 약 1,500줄을 INSERT한다
  • 콜드브루(1010) 15,493줄은 8,204블록 가운데 7,025블록에 흩어져 있다 · 2023-12-15 판매상품 1,498줄
  • CF11_PK (SLE_NO, ITM_NO): BLEVEL 2 · 리프 약 4,290 · CLUSTERING_FACTOR 16,735
  • IX_CF11_ITMNO (ITM_NO): BLEVEL 2 · 리프 약 1,830 · CLUSTERING_FACTOR 387,422 · 이 화면이 쓴다 · 통계 최신
  • 복사본 CF11_NEW: 같은 데이터를 (ITM_NO, SLE_NO) 순으로 쌓고 같은 인덱스를 만든 것 · CF11_PK에 해당하는 인덱스의 CF 1,050,135 · (ITM_NO) 인덱스의 CF 약 8,200

원본 SQL ​

sql
-- S1 「메뉴 월별 판매 추이」 (MD · 하루 수백 번)
SELECT SUBSTR(SLE_NO, 1, 6) AS ym, SUM(SLE_QTY) AS qty, SUM(SLE_QTY * SLE_UPRC) AS amt
  FROM CF11
 WHERE ITM_NO = :v_itm
 GROUP BY SUBSTR(SLE_NO, 1, 6)
 ORDER BY ym;

-- S2 「영수증 상세」 (매장 POS 재출력 · 하루 수천 번)
SELECT ITM_NO, SLE_QTY, SLE_UPRC
  FROM CF11
 WHERE SLE_NO = :v_sle_no;

-- S3 「일 판매상품 집계」 (매장 마감 화면과 야간 마감 · 하루 수백 번)
SELECT ITM_NO, SUM(SLE_QTY) AS qty
  FROM CF11
 WHERE SLE_NO >= :v_dt
   AND SLE_NO <  :v_next_dt
 GROUP BY ITM_NO;

-- 제안서
CREATE TABLE CF11_NEW AS SELECT * FROM CF11 ORDER BY ITM_NO, SLE_NO;

실행계획 학습용 예시 · 건수는 적재 데이터(CF11) 그대로 · 재적재 뒤 숫자는 같은 데이터를 메뉴 순으로 다시 쌓았다고 보고 센 값 ​

xplan
[S1 · 콜드브루 1010 · 지금]
----------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |               |      1 |        |     24 |00:00:00.06 |    7053 |
|   1 |  SORT GROUP BY                       |               |      1 |     24 |     24 |00:00:00.06 |    7053 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| CF11          |      1 |  12463 |  15493 |00:00:00.05 |    7053 |
|*  3 |    INDEX RANGE SCAN                  | IX_CF11_ITMNO |      1 |  12463 |  15493 |00:00:00.01 |      28 |
----------------------------------------------------------------------------------------------------------------
   3 - access("ITM_NO"=:V_ITM)

[S3 · 2023-12-15 · 지금]
----------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |               |      1 |        |     62 |00:00:00.01 |      32 |
|   1 |  HASH GROUP BY                       |               |      1 |     88 |     62 |00:00:00.01 |      32 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| CF11          |      1 |   1500 |   1498 |00:00:00.01 |      32 |
|*  3 |    INDEX RANGE SCAN                  | CF11_PK       |      1 |   1500 |   1498 |00:00:00.01 |       8 |
----------------------------------------------------------------------------------------------------------------
   3 - access("SLE_NO">=:V_DT AND "SLE_NO"<:V_NEXT_DT)

[같은 SQL 을 복사본 CF11_NEW 에서 · Buffers]
  S1 콜드브루      7,053  →    144
  S2 영수증 한 장      4  →  약 5     (한 장의 줄이 평균 2.2블록에 흩어진다)
  S3 하루 1,498줄     32  →  1,438
  (참고) 한 달 46,322줄 집계: 약 890 → 인덱스 경로 약 44,700 · 옵티마이저는 FULL 8,204를 고른다

문제 ​

  1. 제안대로 다시 쌓으면 S1, S2, S3의 Buffers가 어떻게 바뀌는지 복사본의 측정값과 CLUSTERING_FACTOR로 설명하시오. 한 테이블에서 CF11_PK와 (ITM_NO) 인덱스의 CF가 함께 좋을 수 없는 이유도 설명하시오.
  2. 제안을 받아들일지 판단하고, S1을 빠르게 하는 대안을 SQL과 DDL로 작성하시오. 대안의 대가도 적으시오.
  3. 다시 쌓았을 때의 효과가 시간이 지나면 어떻게 되는지, POS가 판매를 쌓는 방식을 근거로 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자