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

주문상품 정제 적재를 작업 8개로 나눴는데 3분 10초가 2분 31초로밖에 줄지 않고 디스크 읽기는 여덟 배가 됐다

기초INSERT버거487 / 700

상황 ​

버거원 분석 DB는 매월 1일 01:00에 주문상품 전체를 DW 전송용 정제 테이블 DW_ORD_ITEM_CLN에 다시 담는다. 한 문장으로 3분 10초가 걸렸고, 01:30에 DW 전송이 시작되므로 데이터가 늘면 겹칠 것이 걱정이었다. 분석 DB는 Standard Edition 2라 병렬 쿼리와 병렬 DML을 쓸 수 없어서, 개발자가 작업 스케줄러로 작업 8개를 띄우고 ORA_HASH(ORD_NO, 7)로 행을 나눠 맡겼다. 이번 달 실행은 2분 31초였다. 개발자: "여덟 개로 나눴으면 30초 남짓이어야 하는데요." 그 시간 대기의 91%가 direct path read였다.

테이블과 인덱스 ​

  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록(약 432MB) · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS)
  • DW_ORD_ITEM_CLN(정제 테이블, 이 문제용): 인덱스 · 제약 · 트리거 없음 · 적재 전에 TRUNCATE한다. 01:00 ~ 01:30에는 이 배치만 쓴다.
  • 서버는 CPU 4개다. 공유 스토리지라 여러 세션이 함께 읽어도 합쳐서 초당 약 25MB까지 나온다.
  • 배치 계정에는 CREATE JOB 권한이 있다(작업 스케줄러와 DBMS_PARALLEL_EXECUTE를 쓸 수 있다).

원본 SQL ​

sql
-- 매월 1일 01:00 · 작업 8개 (k = 0 ~ 7) 가 각자 아래 문장을 실행하고 커밋한다
INSERT INTO DW_ORD_ITEM_CLN (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS, ORD_YM)
SELECT ORD_NO, ITEM_ID, NVL(ORD_ITEM_QTY, 0), ORD_DT, ORD_HMS, SUBSTR(ORD_DT, 1, 6)
  FROM ORD_ITEM
 WHERE ORA_HASH(ORD_NO, 7) = :k;
COMMIT;

실행계획 학습용 예시 ​

xplan
[작업 하나 (k = 0) — DISPLAY_CURSOR(FORMAT => 'ALLSTATS LAST')]
------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name            | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads |
------------------------------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT         |                 |      1 |        |      0 |00:02:29.61 |   62414 | 55265 |
|   1 |  LOAD TABLE CONVENTIONAL | DW_ORD_ITEM_CLN |      1 |        |      0 |00:02:29.61 |   62414 | 55265 |
|*  2 |   TABLE ACCESS FULL      | ORD_ITEM        |      1 |  24727 |    309K|00:02:18.20 |   55269 | 55265 |
------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(ORA_HASH("ORD_NO",7)=:K)

[작업 8개 — 스케줄러 기록과 세션 통계]
  작업          시작       끝         넣은 행     physical reads
  DW_CLN_0     01:00:02   01:02:31    309,412       55,265
  DW_CLN_1     01:00:02   01:02:33    308,977       55,265
  …            …          …           …             …
  DW_CLN_7     01:00:02   01:02:32    309,106       55,265
  합계                                2,472,717     442,120    (한 문장으로 돌 때 55,265)
  대기: direct path read 91% · CPU 8%

문제 ​

  1. 작업을 8개로 나눴는데도 2분 31초가 걸리고 디스크 읽기가 여덟 배가 된 이유를 실행계획으로 설명하시오.
  2. 작업마다 서로 다른 블록만 읽도록 나누는 방법으로 배치를 다시 작성하시오. 어느 작업이 실패했을 때 어떻게 다시 돌릴지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자