Skip to content
튜닝 연습인덱스 사용 조건
IDX-071

하루 정정 수십 건을 반영하는 정보계 판매 MERGE가 정보계 판매를 통째로 읽는다

중급MERGE유통71 / 700

상황 ​

유통 정보계는 운영 판매(CF10)를 복제한 「정보계 판매」 테이블을 둔다. 매일 01시에 전날 판매를 넣고, 02시에 「판매 정정 반영」 MERGE가 전날 고쳐진 판매(반품 취소, 매장 정정, 늦게 등록된 지난 판매)를 반영한다. 정정은 하루 30 ~ 80건이다. 그런데 MERGE 한 번에 0.8초쯤 걸리고, 정보계 판매가 커질수록 늘어난다. 정보계 DBA는 "PK가 있는데 왜 다 읽느냐"고 묻는다. 아래는 2023-12-15 정정분(52건)을 반영할 때다.

테이블과 인덱스 ​

  • CF10 판매(운영): 500,000행 · 4,583블록 · MOD_DTT DATE(고친 시각) · 인덱스 IX_CF10_MOD (MOD_DTT) (문제 설정: IDX-034와 같다. 판매를 등록하거나 고칠 때마다 MOD_DTT가 찍힌다)
  • DW_SLE 정보계 판매(이 문제에서 쓰는 파생 테이블, CF10의 복제): 500,000행 · 4,640블록 · SLE_NO · SLE_DT · SLE_HMS · SHP_NO · CNCL_DTT · 날짜순으로 쌓인다
  • PK_DW_SLE (SLE_DT, SLE_NO): 정보계 규칙대로 날짜를 맨 앞에 둔 PK · BLEVEL 2 · 리프 약 1,900블록 · 다른 인덱스는 없다
  • 판매번호 앞 8자리는 판매일자다. 판매일자는 정정 대상이 아니다(날짜가 틀린 판매는 취소하고 새로 등록한다)
  • 2023-12-15에 고쳐진 판매 52건: 정보계에 이미 있는 판매 49건, 늦게 등록된 지난 판매 3건

원본 SQL ​

sql
MERGE INTO DW_SLE t
USING (SELECT SLE_NO, SLE_DT, SLE_HMS, SHP_NO, CNCL_DTT
         FROM CF10
        WHERE MOD_DTT >= TO_DATE(:v_ymd, 'YYYYMMDD')
          AND MOD_DTT <  TO_DATE(:v_ymd, 'YYYYMMDD') + 1) s
   ON (t.SLE_NO = s.SLE_NO)
 WHEN MATCHED THEN
   UPDATE SET t.SHP_NO = s.SHP_NO, t.CNCL_DTT = s.CNCL_DTT
 WHEN NOT MATCHED THEN
   INSERT (SLE_NO, SLE_DT, SLE_HMS, SHP_NO, CNCL_DTT)
   VALUES (s.SLE_NO, s.SLE_DT, s.SLE_HMS, s.SHP_NO, s.CNCL_DTT)

실행계획 학습용 예시 ​

xplan
-----------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT                       |             |      1 |        |      0 |00:00:00.84 |    4767 |
|   1 |  MERGE                                | DW_SLE      |      1 |        |      0 |00:00:00.84 |    4767 |
|   2 |   VIEW                                |             |      1 |        |     52 |00:00:00.83 |    4697 |
|*  3 |    HASH JOIN OUTER                    |             |      1 |     41 |     52 |00:00:00.83 |    4697 |
|   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| CF10       |      1 |     41 |     52 |00:00:00.01 |      57 |
|*  5 |      INDEX RANGE SCAN                 | IX_CF10_MOD |      1 |     41 |     52 |00:00:00.01 |       4 |
|   6 |     TABLE ACCESS FULL                 | DW_SLE      |      1 |   500K |   500K |00:00:00.79 |    4640 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T"."SLE_NO"="SLE_NO")
   5 - access("MOD_DTT">=TO_DATE(:V_YMD,'YYYYMMDD') AND "MOD_DTT"<TO_DATE(:V_YMD,'YYYYMMDD')+1)

문제 ​

  1. PK가 있는데도 정보계 판매를 통째로 읽는 이유를 ON 절의 조건과 PK의 선두 컬럼으로 설명하시오.
  2. 결과가 바뀌지 않게 MERGE를 고쳐 PK로 찾아가게 하고, 그렇게 고쳐도 되는 근거를 설명하시오.
  3. 정보계 판매가 계속 커질 때 고치기 전과 고친 뒤의 비용이 각각 무엇에 비례하는지 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자