Skip to content
튜닝 연습Lock과 동시성 제어
LOCK-025

고객 정보를 열어 두기만 했는데 등급 재산정 배치가 50분을 기다렸다

기초UPDATE한빛유통520 / 700

상황 ​

한빛유통 고객센터의 상담 프로그램(설치형 클라이언트)은 상담원이 고객을 조회할 때 개인정보 접근 기록을 남긴다. 작년 개인정보 점검 뒤 M_CUS에 컬럼 둘을 더하고, 조회할 때마다 그 고객 행을 UPDATE하게 바꿨다. COMMIT은 상담원이 「저장」 버튼을 누를 때만 한다. 7월 1일 12:00에 돈 「고객 등급 재산정」 배치가 12:51에야 끝났다(평소 3초). 그 사이 다른 상담원 둘의 고객 조회 화면도 멈췄다. 상담원들은 점심시간이라 아무것도 하지 않았다고 한다.

테이블과 인덱스 ​

  • M_CUS 고객: 2,000행 · 30블록 · PK_M_CUS (CUS_ID) · 작년에 더한 LST_INQ_DT(마지막 조회 시각), LST_INQ_EMP(조회한 상담원)
  • 상담 프로그램은 상담원 한 명이 DB 세션 하나를 계속 쥔다(자동 COMMIT 꺼짐).
  • 등급 재산정 배치는 매일 12:00에 고객 2,000명의 CUS_GD를 한 문장으로 고치고 COMMIT한다.
  • 개인정보 점검 요구 원문: "개인정보 조회 이력(조회자, 조회 시각, 대상)을 1년 보관할 것"

원본 SQL ​

sql
-- 상담 프로그램: 고객 조회 (상담원이 고객을 열 때마다)
SELECT CUS_ID, CUS_NM, RGN_ID, GND_TP, BTH_YMD, CUS_GD
  FROM M_CUS
 WHERE CUS_ID = :cus_id;

UPDATE M_CUS
   SET LST_INQ_DT = SYSDATE, LST_INQ_EMP = :emp_id     -- 개인정보 접근 기록 (작년 점검 조치)
 WHERE CUS_ID = :cus_id;
-- COMMIT 은 「저장」 버튼에서만 (조회만 하고 넘어가면 다음 저장 때 함께)

-- 12:00 「고객 등급 재산정」 배치 (평소 3초)
MERGE INTO M_CUS c
USING (SELECT CUS_ID,
              CASE WHEN SUM(ORD_AMT) >= 5000000 THEN 'A'
                   WHEN SUM(ORD_AMT) >= 1000000 THEN 'B' ELSE 'C' END AS NEW_GD
         FROM T_ORD
        WHERE ORD_DT >= ADD_MONTHS(TRUNC(SYSDATE), -12)
        GROUP BY CUS_ID) s
   ON (c.CUS_ID = s.CUS_ID)
 WHEN MATCHED THEN UPDATE SET c.CUS_GD = s.NEW_GD;
COMMIT;

실행계획 학습용 예시 · 블로킹 트리 쿼리는 교재 12화 §5 ​

xplan
[블로킹 트리 — 7월 1일 12:20:05]
SID_TREE   PROGRAM            STATUS     EVENT                            SECS    BLOCKER   SQL_ID 의 문장 / PREV_SQL_ID 의 문장
77         CSCLIENT.exe       INACTIVE   SQL*Net message from client      1,207             (없음) / UPDATE M_CUS SET LST_INQ_DT = SYSDATE …
  203      JDBC Thin Client   ACTIVE     enq: TX - row lock contention    1,203   77        MERGE INTO M_CUS c USING …
    18     CSCLIENT.exe       ACTIVE     enq: TX - row lock contention      640   203       UPDATE M_CUS SET LST_INQ_DT = SYSDATE … (CUS_000412)
    41     CSCLIENT.exe       ACTIVE     enq: TX - row lock contention      312   203       UPDATE M_CUS SET LST_INQ_DT = SYSDATE … (CUS_000377)

[V$LOCK — 같은 시각]
SID   TYPE  대상                  LMODE  REQUEST  BLOCK
77    TM    M_CUS                   3      0        0
77    TX    SID 77 의 트랜잭션        6      0        1
203   TM    M_CUS                   3      0        0
203   TX    배치의 트랜잭션           6      0        1      ← 이미 고친 고객 1,286명의 행
203   TX    SID 77 의 트랜잭션        0      6        0      ← CUS_001287 에서 멈췄다
18    TX    배치의 트랜잭션           0      6        0
41    TX    배치의 트랜잭션           0      6        0

[V$TRANSACTION ⋈ V$SESSION — SID 77]
  START_TIME 11:59:58 · USED_UREC 1 (행 하나) · 상담원 7번 자리
  11:59:58 고객 CUS_001287 조회 · 그 뒤 실행한 SQL 0개 (화면을 열어 둔 채 점심)

[12:51:40]  상담원 7번이 돌아와 다른 고객을 조회하고 「저장」 → COMMIT → 12:51:43 배치 끝 → 18 · 41 진행

문제 ​

  1. 블로킹 트리와 V$LOCK, V$TRANSACTION을 근거로 배치가 무엇을 50분 동안 기다렸는지 설명하시오. 막은 세션이 아무 SQL도 실행하지 않는데 락을 쥐고 있던 이유도 쓰시오.
  2. 개인정보 점검 요구를 지키면서 조회 화면이 행 락을 남기지 않도록 고치시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자