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

회원 동기화에 조건을 붙였더니 생년월일을 새로 입력한 고객이 DW로 넘어가지 않는다

중급MERGE한빛유통450 / 700

상황 ​

한빛유통은 매일 01:00에 회원계(CRM)가 보낸 고객 전체 파일(STG_CUS)을 M_CUS에 맞추고, 02:00에 DW가 UPD_DT가 어제인 고객을 변경분으로 가져간다. 처음 판은 MERGE가 날마다 2,000명 전원의 UPD_DT를 고쳐서, DW 고객 이력에 하루 2,000행씩 새 버전이 쌓였다(실제로 바뀐 고객은 하루 10명 안팎이다). 그래서 개발자가 WHEN MATCHED에 <> 비교 조건을 붙였다. 변경분은 하루 8명으로 줄었는데, 이번에는 정산팀 조민우가 문의를 했다. "생년월일을 새로 입력한 고객 세 명이 DW에 안 넘어왔어요."

테이블과 인덱스 ​

  • M_CUS: 2,000행 · 30블록 · PK_M_CUS (CUS_ID) · 이 문제에서는 UPD_DT DATE 칸이 더 있다(DW 변경분 추출 기준)
  • RGN_ID, GND_TP, BTH_YMD는 NULL을 허용한다(회원이 입력하지 않으면 NULL). CUS_NM은 NOT NULL이다.
  • STG_CUS: 회원계가 매일 보내는 전체 고객 파일 · 2,000행 · 30블록 · CUS_ID는 적재할 때 유일성을 검사한다
  • 회원계 변경 로그로 센 어제의 실제 변경은 12명이다(이름 2, 지역 6, 생년월일 NULL에서 값으로 3, 성별 값에서 NULL로 1).
  • CUS_GD는 회원계가 아니라 한빛유통 등급 배치가 정하므로 동기화하지 않는다.

원본 SQL ​

sql
MERGE INTO M_CUS c
USING STG_CUS s
   ON (c.CUS_ID = s.CUS_ID)
 WHEN MATCHED THEN UPDATE
      SET c.CUS_NM  = s.CUS_NM,
          c.RGN_ID  = s.RGN_ID,
          c.GND_TP  = s.GND_TP,
          c.BTH_YMD = s.BTH_YMD,
          c.UPD_DT  = SYSDATE
    WHERE c.CUS_NM  <> s.CUS_NM          -- 지난주에 붙인 조건 (바뀐 고객만)
       OR c.RGN_ID  <> s.RGN_ID
       OR c.GND_TP  <> s.GND_TP
       OR c.BTH_YMD <> s.BTH_YMD
 WHEN NOT MATCHED THEN INSERT (CUS_ID, CUS_NM, RGN_ID, GND_TP, BTH_YMD, CUS_GD, UPD_DT)
      VALUES (s.CUS_ID, s.CUS_NM, s.RGN_ID, s.GND_TP, s.BTH_YMD, 'C', SYSDATE);

실행계획 학습용 예시 ​

xplan
[어제 밤 같은 파일 — 판별 비교]
                    MERGE 갱신 행   DW 변경분   회원계 변경 로그
  처음 판 (조건 없음)        2,000       2,000          12
  지금 판 (<> 조건)              8           8          12   (빠진 4명: 생년월일 NULL → 값 3 · 성별 값 → NULL 1)

------------------------------------------------------------------------------------------
| Id  | Operation            | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT      |         |      1 |        |      0 |00:00:00.02 |      74 |
|   1 |  MERGE               | M_CUS   |      1 |        |      0 |00:00:00.02 |      74 |
|   2 |   VIEW               |         |      1 |        |   2000 |00:00:00.01 |      62 |
|*  3 |    HASH JOIN OUTER   |         |      1 |   2000 |   2000 |00:00:00.01 |      62 |
|   4 |     TABLE ACCESS FULL| STG_CUS |      1 |   2000 |   2000 |00:00:00.01 |      31 |
|   5 |     TABLE ACCESS FULL| M_CUS   |      1 |   2000 |   2000 |00:00:00.01 |      31 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("C"."CUS_ID"="S"."CUS_ID")

문제 ​

  1. 처음 판이 매일 2,000명을 변경분으로 넘긴 이유와, 지금 판이 4명을 놓친 이유를 설명하시오.
  2. 실제로 바뀐 고객만 빠짐없이 고치도록 MERGE를 고치고, 결과가 맞는지 어떻게 확인할지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자