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

매장 하나의 시각을 정정했는데 104,864건이 갱신됐다

중급MERGE버거427 / 700

상황 ​

무대는 버거원 POS 본사 DB다. SH0137 매장 POS의 시계가 2013년 3월 한 달 동안 1시간 늦어서, 실제보다 1시간 이른 시각이 찍혔다. 주문(ORD)의 ORD_HMS는 본사가 이미 1시간씩 더해 정정했다(3월 31일 23시대에 찍힌 몇 건은 ORD_DT도 4월 1일로 바꿨다). 주문상품(ORD_ITEM)에는 같은 두 칸이 복사돼 있어서(반정규화) 그것도 맞춰야 한다. 개발팀이 넘긴 SQL을 반영 리허설(운영 복제본)에서 돌렸더니 8초가 걸렸고 104,864건이 갱신됐다. 테스트 DB에는 SH0137의 3월 주문만 넣어 두고 시험해서 건수를 확인하지 못했다.

테이블과 인덱스 ​

  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · 2013년 3월분 104,864행. ORD_DT와 ORD_HMS는 NULL을 허용한다(NOT NULL 제약 없음).
  • 인덱스 ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS)
  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_PK (ORD_NO) 유일 · ORD_X01 (ORD_DT, ORD_HMS) · 200개 매장
  • 정정된 SH0137 주문은 212건(정정 뒤 날짜 3/1 ~ 4/1)이고, 그 주문상품은 524행이다. 통계는 최신이다.

원본 SQL ​

sql
UPDATE ORD_ITEM i
   SET i.ORD_DT  = (SELECT o.ORD_DT  FROM ORD o
                     WHERE o.ORD_NO = i.ORD_NO AND o.SHOP_NO = 'SH0137'),
       i.ORD_HMS = (SELECT o.ORD_HMS FROM ORD o
                     WHERE o.ORD_NO = i.ORD_NO AND o.SHOP_NO = 'SH0137')
 WHERE i.ORD_DT BETWEEN '20130301' AND '20130331';

실행계획 학습용 예시 ​

xplan
Plan hash value: 1880412637

------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT                      |              |      1 |        |      0 |00:00:08.12 |   1214K |
|   1 |  UPDATE                               | ORD_ITEM     |      1 |        |      0 |00:00:08.12 |   1214K |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED | ORD_ITEM     |      1 |    106K|    104K|00:00:00.21 |    2812 |
|*  3 |    INDEX RANGE SCAN                   | ORD_ITEM_X01 |      1 |    106K|    104K|00:00:00.04 |     402 |
|*  4 |   TABLE ACCESS BY INDEX ROWID         | ORD          |    104K|      1 |    524 |00:00:00.61 |    319K |
|*  5 |    INDEX UNIQUE SCAN                  | ORD_PK       |    104K|      1 |    104K|00:00:00.28 |    214K |
|*  6 |   TABLE ACCESS BY INDEX ROWID         | ORD          |    104K|      1 |    524 |00:00:00.58 |    319K |
|*  7 |    INDEX UNIQUE SCAN                  | ORD_PK       |    104K|      1 |    104K|00:00:00.27 |    214K |
------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("I"."ORD_DT">='20130301' AND "I"."ORD_DT"<='20130331')
   4 - filter("O"."SHOP_NO"='SH0137')
   5 - access("O"."ORD_NO"=:B1)
   6 - filter("O"."SHOP_NO"='SH0137')
   7 - access("O"."ORD_NO"=:B1)

[리허설 뒤 — 같은 복제본에서 센 것]
  갱신된 행                              104,864
  ORD_DT · ORD_HMS 가 NULL 이 된 행      104,340
  redo size                              약 61 MB

문제 ​

  1. Buffers 1,214K가 어디서 나오는지 실행계획의 Starts로 설명하시오.
  2. 리허설 뒤 104,340행에 무슨 일이 일어났는지, 원본 SQL의 어느 부분 때문인지 설명하시오.
  3. ORD를 한 번 조인해서 정정된 주문의 주문상품만 고치는 SQL로 다시 작성하고, 그 SQL이 안전하려면 무엇이 보장돼야 하는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자