Skip to content
튜닝 연습파티션
PART-047

2022년 주문의 고객번호를 가명으로 바꾸는 UPDATE, 병렬로 돌려도 redo 186MB와 두 배가 된 인덱스는 그대로다

실전UPDATE한빛유통422 / 700

상황 ​

법무팀 지침에 따라 한빛유통은 주문 후 2년이 지난 주문의 고객번호를 가명으로 바꾼다. 처음에는 2022년 한 해(12칸)를 한꺼번에 처리하고, 그 뒤로는 매달 한 칸씩 처리한다. 2022년 주문이 등급별 분석에서 빠져도 된다는 것은 현업이 확인했다. 조민우가 UPDATE 한 문장을 올렸고 EE 시험 DB에서 두 번 리허설했다. 직렬로는 58초, 병렬 DML로는 14초에 끝났지만 redo와 undo는 거의 같았고, 끝난 뒤 고객번호 인덱스의 2022년 칸이 두 배로 커졌다. 박팀장: "UPDATE 말고 칸 단위로 하는 방법까지 비교해서, 2022년 일괄 처리와 매달 처리를 어떻게 할지 정해 와."

테이블과 인덱스 ​

  • T_ORD_BIG_P14 주문(파티션 복사본, 교재 14화): 1,000,000행 · PARTITION BY RANGE (ORD_DT) 월별 36칸(P202201 ~ P202412)과 빈 PMAX. 2022년은 1 ~ 12번째 칸이고 333,120행, 칸 하나 FULL ≈ 161블록이다. 컬럼은 ORD_SEQ · CUS_ID · ORD_DT · ORD_ST · ORD_AMT다.
  • LOCAL 인덱스 IX_P14_CUS_DT (CUS_ID, ORD_DT)(2022년 12칸의 리프 합계 약 1,150블록) · IX_P14_DT_AMT (ORD_DT, ORD_AMT). 제약, GLOBAL 인덱스, 트리거는 없다.
  • T_CUS_PSN 가명 매핑(문제 설정): 2,000행 · 12블록 · CUS_ID → PSN_ID VARCHAR2(12) · PK PK_T_CUS_PSN (CUS_ID). 법무팀이 만들어 넘겼고 2022년 주문의 고객이 모두 들어 있다고 한다.
  • 낮에는 결제 화면이 이번 달 칸의 ORD_ST를 한 건씩 고치고, 고객센터가 가끔 지난 주문의 반품을 처리한다. 운영은 ARCHIVELOG다.

원본 SQL ​

sql
-- 리허설 ① 직렬
UPDATE T_ORD_BIG_P14 o
   SET o.CUS_ID = (SELECT m.PSN_ID FROM T_CUS_PSN m WHERE m.CUS_ID = o.CUS_ID)
 WHERE o.ORD_DT >= DATE '2022-01-01'
   AND o.ORD_DT <  DATE '2023-01-01';
COMMIT;

-- 리허설 ② 병렬 DML
ALTER SESSION ENABLE PARALLEL DML;
UPDATE /*+ PARALLEL(o 8) */ T_ORD_BIG_P14 o
   SET o.CUS_ID = (SELECT m.PSN_ID FROM T_CUS_PSN m WHERE m.CUS_ID = o.CUS_ID)
 WHERE o.ORD_DT >= DATE '2022-01-01'
   AND o.ORD_DT <  DATE '2023-01-01';
COMMIT;

실행계획 학습용 예시 · EE 시험 DB 기준 · 병렬 수치는 어림값 ​

xplan
[① 직렬 UPDATE]
-----------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name          | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
-----------------------------------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT              |               |      1 |        |      0 | 00:00:57.84 |    1421K|        |       |
|   1 |  UPDATE                       | T_ORD_BIG_P14 |      1 |        |      0 | 00:00:57.84 |    1421K|        |       |
|   2 |   PARTITION RANGE ITERATOR    |               |      1 |   333K |   333K | 00:00:00.21 |    1932 |      1 |    12 |
|*  3 |    TABLE ACCESS FULL          | T_ORD_BIG_P14 |     12 |   333K |   333K | 00:00:00.17 |    1932 |      1 |    12 |
|   4 |   TABLE ACCESS BY INDEX ROWID | T_CUS_PSN     |   2377 |      1 |   2377 | 00:00:00.01 |    4754 |        |       |
|*  5 |    INDEX UNIQUE SCAN          | PK_T_CUS_PSN  |   2377 |      1 |   2377 | 00:00:00.01 |    2377 |        |       |
-----------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter(("O"."ORD_DT">=TO_DATE(' 2022-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "O"."ORD_DT"<TO_DATE(' 2023-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
   5 - access("M"."CUS_ID"=:B1)

[세션 통계 · 리허설 두 번]
                               ① 직렬            ② 병렬 DML (DOP 8)
  경과                          57.8초            14.2초
  redo size                    약 182 MB         약 186 MB
  undo change vector size      약 96 MB          약 97 MB
  db block changes             약 1,340,000      약 1,350,000
  다른 세션                     -                 고객센터의 2022년 주문 반품 처리 2건이 끝날 때까지 enq: TM - contention

[끝난 뒤 · IX_P14_CUS_DT 의 2022년 12칸]
  리프 블록 합계 약 1,150 → 약 2,240 (옛 키를 지운 빈자리는 남고, 새 키는 다른 자리에 끼워 넣느라 블록이 쪼개졌다)

문제 ​

  1. 리허설의 redo와 undo, 인덱스 크기가 어디서 나오는지 설명하고, 병렬 DML이 무엇을 줄였고 무엇을 줄이지 못했는지 쓰시오.
  2. 칸마다 가명으로 바꾼 행을 새 테이블에 쓰고 그 칸과 맞바꾸는 방법으로 SQL을 작성하시오. 결과가 원본 UPDATE와 같으려면 무엇을 먼저 확인해야 하는지도 쓰시오.
  3. ① 직렬 UPDATE, ② 병렬 DML, ③ 칸마다 교환을 경과 시간, redo와 undo, 인덱스, 잠금, 실패했을 때의 상태로 비교하고 2022년 일괄 처리와 매달 처리에 각각 무엇을 쓸지 정하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자