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

토요일 밤 2022년 주문을 정리한 뒤로 등급별 매출 화면이 어떤 때는 0.3초, 어떤 때는 4초다

중급DDL한빛유통466 / 700

상황 ​

운영 DBA가 지난 토요일 밤 T_ORD_BIG에서 2022년 주문(3분의 1)을 정리했다. DELETE 대신 2023년 이후만 새 테이블로 옮기고 이름을 바꿔 끼웠고, 빨리 끝내려고 테이블과 인덱스를 모두 PARALLEL 8 NOLOGGING으로 만들었다. 작업은 4분 만에 끝났다. 월요일 오전부터 등급별 매출 화면(시간당 약 200번 호출)의 응답 시간이 들쭉날쭉하고 DB 서버 CPU가 90%를 넘나든다. 같은 날 08:10, 리포트용 대기 DB에서는 월간 리포트가 블록 손상 에러로 실패했다.

테이블과 인덱스 ​

  • T_ORD_BIG(정리 뒤): 666,971행 · 약 3,890블록 · ORD_DT 2023-01-01 ~ 2024-12-31 · 전부 자정
  • 인덱스 IX_ORD_BIG_DT_AMT (ORD_DT, ORD_AMT) · IX_ORD_BIG_DT_SEQ (ORD_DT, ORD_SEQ)(정리 때 새로 만들었다)
  • M_CUS 고객: 2,000행 · 30블록 · CUS_GD A 1% · B 9% · C 90%
  • 운영은 EE이고 병렬 실행이 켜져 있다(parallel_max_servers 32). 운영 DB는 ARCHIVELOG이고 FORCE_LOGGING은 NO다. 리포트용 대기 DB(Active Data Guard)가 운영의 redo를 받아 따라간다.

원본 SQL ​

sql
-- 토요일 23:00 · 2022년 주문 정리 (운영 DBA)
CREATE TABLE T_ORD_BIG_N
  PARALLEL 8 NOLOGGING
AS SELECT * FROM T_ORD_BIG WHERE ORD_DT >= DATE '2023-01-01';

CREATE INDEX IX_ORD_BIG_N_DT_AMT ON T_ORD_BIG_N (ORD_DT, ORD_AMT) PARALLEL 8 NOLOGGING;
CREATE INDEX IX_ORD_BIG_N_DT_SEQ ON T_ORD_BIG_N (ORD_DT, ORD_SEQ) PARALLEL 8 NOLOGGING;

ALTER TABLE T_ORD_BIG RENAME TO T_ORD_BIG_OLD;
ALTER TABLE T_ORD_BIG_N RENAME TO T_ORD_BIG;
ALTER INDEX IX_ORD_BIG_DT_AMT RENAME TO IX_ORD_BIG_OLD_DT_AMT;
ALTER INDEX IX_ORD_BIG_DT_SEQ RENAME TO IX_ORD_BIG_OLD_DT_SEQ;
ALTER INDEX IX_ORD_BIG_N_DT_AMT RENAME TO IX_ORD_BIG_DT_AMT;
ALTER INDEX IX_ORD_BIG_N_DT_SEQ RENAME TO IX_ORD_BIG_DT_SEQ;
GRANT SELECT ON T_ORD_BIG TO STLM_APP;
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T_ORD_BIG')

실행계획 학습용 예시 · 병렬 계획은 EE 모양(교재 14화 §9.3) ​

xplan
[월요일 10:00 · 등급별 매출 화면 (힌트 없는 같은 SQL) — 계획 모양만]
SELECT c.CUS_GD, SUM(o.ORD_AMT) FROM T_ORD_BIG o JOIN M_CUS c ON c.CUS_ID = o.CUS_ID GROUP BY c.CUS_GD

| Id | Operation                       | Name      |    TQ  | IN-OUT | PQ Distrib |
|  0 | SELECT STATEMENT                |           |        |        |            |
|  1 |  PX COORDINATOR                 |           |        |        |            |
|  2 |   PX SEND QC (RANDOM)           | :TQ10002  |  Q1,02 | P->S   | QC (RAND)  |
|  3 |    HASH GROUP BY                |           |  Q1,02 | PCWP   |            |
|  4 |     PX RECEIVE                  |           |  Q1,02 | PCWP   |            |
|  5 |      PX SEND HASH               | :TQ10001  |  Q1,01 | P->P   | HASH       |
|  6 |       HASH GROUP BY             |           |  Q1,01 | PCWP   |            |
|* 7 |        HASH JOIN                |           |  Q1,01 | PCWP   |            |
|  8 |         PX RECEIVE              |           |  Q1,01 | PCWP   |            |
|  9 |          PX SEND BROADCAST      | :TQ10000  |  Q1,00 | S->P   | BROADCAST  |
| 10 |           PX SELECTOR           |           |  Q1,00 | SCWC   |            |
| 11 |            TABLE ACCESS FULL    | M_CUS     |  Q1,00 | SCWP   |            |
| 12 |         PX BLOCK ITERATOR       |           |  Q1,01 | PCWC   |            |
| 13 |          TABLE ACCESS FULL      | T_ORD_BIG |  Q1,01 | PCWP   |            |
Note
-----
   - Degree of Parallelism is 8 because of table property

[같은 화면 · 지난주와 이번 주]
                        지난주 금요일             이번 주 월요일
  경과 (화면 한 번)      0.31 초                  0.4 ~ 4.1 초
  계획                   직렬 HASH JOIN · 5,868   위 PX 계획 (DOP 8)

[V$SYSSTAT · 월요일 09:00 ~ 11:00]
  queries parallelized                          2,388
  Parallel operations downgraded to serial        412
  Parallel operations downgraded 75 to 99 pct     131

[딕셔너리 — 운영]
  USER_TABLES   T_ORD_BIG          DEGREE 8 · LOGGING NO
  USER_INDEXES  IX_ORD_BIG_DT_AMT  DEGREE 8 · LOGGING NO
                IX_ORD_BIG_DT_SEQ  DEGREE 8 · LOGGING NO

[리포트용 대기 DB · 월요일 08:10 월간 리포트]
  ORA-01578: ORACLE data block corrupted (file # 7, block # 29441)
  ORA-26040: Data block was loaded using the NOLOGGING option

문제 ​

  1. 힌트도 없는 화면 SQL이 병렬로 돌게 된 이유와, 응답 시간이 들쭉날쭉한 이유를 위 숫자로 설명하시오.
  2. 대기 DB의 리포트가 실패한 이유를 설명하시오.
  3. 두 문제를 바로잡는 SQL을 작성하고, 다음에 같은 정리를 할 때 스크립트에 무엇을 넣어야 하는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자