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

배달 정보를 소급해 채운 뒤 일별 배달 현황이 12배 블록을 읽는데, 클러스터링 팩터는 그대로다

실전DDL버거482 / 700

상황 ​

버거원 본사는 2014년 1월 배달앱 연동을 시작하면서, 첫 주말에 2013년 배달 주문 약 20만 건의 배달 정보를 ORD에 한 번에 소급해 채웠다. 그 뒤로 본사 「일별 배달 현황」이 2013년 날짜에서만 느려졌다. DBA가 점검했더니 통계는 최신이고 ORD_X01의 클러스터링 팩터도 22,223 그대로였다. 정리 방법으로 넷이 올라왔다. (A) ALTER TABLE ORD MOVE (B) ALTER TABLE ORD MOVE ONLINE (C) 새 테이블에 날짜순으로 다시 쌓아 바꿔 끼우기 (D) DBMS_REDEFINITION 온라인 재정의. 매장 영업은 10:00 ~ 24:00이고, 02:00 ~ 06:00에는 POS 입력이 없다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 배달 칸을 채우기 전 22,422블록 · 날짜순 적재 · 하루 약 1,370건 · 행 길이 약 160바이트 · ORD_PK (ORD_NO) · ORD_X01 (ORD_DT, ORD_HMS) CF 22,223
  • 이 문제에서는 DLV_YN VARCHAR2(1)와 DLV_INFO VARCHAR2(200) 칸이 더 있다. 2013년 배달 주문 200,410건에 DLV_INFO가 평균 약 140바이트 들어갔다. PCTFREE는 기본값 10이다.
  • 지금(ANALYZE): BLOCKS 25,652 · CHAIN_CNT 78,412(전부 2013년 배달 주문)
  • 앞으로도 새 배달 주문은 POS가 넣은 뒤 몇 분 안에 배달앱 서버가 DLV_INFO를 채운다.
  • POS 연동 계정 POS_IF에 SELECT, INSERT, UPDATE 권한이 있다. 테이블 여유 공간은 테이블 크기의 세 배쯤 남아 있다.

원본 SQL ​

sql
-- 2014년 1월 첫 주말 · 2013년 배달 정보 소급 (배달앱 연동팀)
UPDATE ORD o
   SET o.DLV_YN   = 'Y',
       o.DLV_INFO = (SELECT d.DLV_INFO FROM DLV_HIST_2013 d WHERE d.ORD_NO = o.ORD_NO)
 WHERE o.ORD_DT BETWEEN '20130101' AND '20131231'
   AND EXISTS (SELECT 1 FROM DLV_HIST_2013 d WHERE d.ORD_NO = o.ORD_NO);
COMMIT;

-- 본사 「일별 배달 현황」
SELECT SUBSTR(ORD_HMS, 1, 2) AS HH, COUNT(*) AS ORD_CNT,
       COUNT(CASE WHEN DLV_YN = 'Y' THEN 1 END) AS DLV_CNT
  FROM ORD
 WHERE ORD_DT = :v_dt
 GROUP BY SUBSTR(ORD_HMS, 1, 2);

실행계획 학습용 예시 · MOVE 뒤 숫자의 비율은 교재 05화 실측(MOVE 후 CF 52,206 · Buffers 10,405)과 같은 모양 ​

xplan
[일별 배달 현황 — :v_dt = '20131105']
----------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |         |      1 |        |     14 |00:00:00.02 |     453 |
|   1 |  HASH GROUP BY                       |         |      1 |     14 |     14 |00:00:00.02 |     453 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| ORD     |      1 |   1370 |   1372 |00:00:00.02 |     453 |
|*  3 |    INDEX RANGE SCAN                  | ORD_X01 |      1 |   1370 |   1372 |00:00:00.01 |       5 |
----------------------------------------------------------------------------------------------------------

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

  table fetch continued row   214 (한 번 실행할 때)
  (같은 SQL · :v_dt = '20121105' → A-Rows 1,366 · Buffers 36 · continued row 0)

[시험 DB 사본에서 넷을 해 본 결과]
  방법                        CHAIN_CNT   BLOCKS    ORD_X01 CF   일별 현황 Buffers   POS 입력        작업 시간
  지금                          78,412    25,652       22,223         453              —               —
  (A) MOVE + REBUILD                 0    26,318       72,540         171              멈춤            약 1분 40초
  (B) MOVE ONLINE                    0    26,318       72,610         171              계속 받음       약 4분 10초
  (C) CTAS ORDER BY + 바꿔 끼우기      0    26,302       26,014          44              멈춤            약 2분 30초
  (D) DBMS_REDEFINITION (ORDERBY_COLS)  0  26,302       26,020          44              계속 받음       약 9분 (준비와 끝맺음 포함)

문제 ​

  1. 일별 배달 현황이 느려진 원인을 설명하고, 클러스터링 팩터가 22,223 그대로인데도 느린 이유를 쓰시오.
  2. 정리안 넷을 숫자와 부작용으로 비교해 하나를 고르고, 그 SQL을 작성하시오. MOVE가 행 이전을 없애는데도 일별 현황이 171블록에 머무는 이유를 쓰시오.
  3. 앞으로 다시 생기지 않게 하는 방법을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자