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

월요일 10시 40분, 정산 화면 스물여섯 개가 멈췄는데 블로킹 트리의 뿌리가 둘이다

실전SELECT한빛유통543 / 700

상황 ​

월요일 10:40에 정산팀과 고객센터에서 동시에 전화가 왔다. 정산 화면은 등록도 정정도 안 되고, 고객센터의 「결제 수단 변경」은 몇 분째 돌고, 정산 대사 리포트는 평소 2초인데 1분이 넘도록 끝나지 않는다. DBA가 10:41:30에 블로킹 트리와 V$LOCK, V$TRANSACTION을 찍어 보냈다. 박팀장의 주문이다. "누구를 끊고 누구를 기다릴지, 그 순서와 근거를 5분 안에 적어 와. 그리고 다음엔 이런 일이 안 생기게 해."

테이블과 인덱스 ​

  • T_ORD_STLM 정산: 100,000행 · 640블록 · PK_T_ORD_STLM (STLM_SEQ) · 정산 화면이 등록(INSERT)하고 정정(UPDATE)한다
  • T_ORD 주문: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ) · 고객센터가 결제 수단을 바꾼다(UPDATE)
  • 「결제 대사 반영」 배치: PG사 대사 결과로 주문 약 3만 건의 결제 정보를 고친다. 평소 10:20에 시작해 25분 걸리고, 끝에 한 번 COMMIT한다
  • 개발팀은 오늘 10:35에 「정산 정정 사유」 컬럼을 더하는 패치를 걸어 두었다(DDL_LOCK_TIMEOUT 900)
  • 정산 WAS의 커넥션 풀은 40개다

원본 SQL ​

sql
-- DBA 가 10:41:30 에 돌린 블로킹 트리 (교재 12화 §5)
SELECT LPAD(' ', 2 * (LEVEL - 1)) || s.sid AS sid_tree,
       s.serial#, s.program, s.status, s.event, s.seconds_in_wait AS secs,
       s.blocking_session AS blocker, s.sql_id, s.prev_sql_id
  FROM v$session s
 WHERE s.blocking_session IS NOT NULL
    OR s.sid IN (SELECT blocking_session FROM v$session WHERE blocking_session IS NOT NULL)
 START WITH s.blocking_session IS NULL
 CONNECT BY PRIOR s.sid = s.blocking_session
 ORDER SIBLINGS BY s.sid;

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

xplan
[블로킹 트리 — 10:41:30]
SID_TREE   SERIAL#  PROGRAM            STATUS     EVENT                            SECS   하는 문장 (막힌 쪽) / 마지막 문장 (뿌리)
131        2207     SQL Developer      INACTIVE   SQL*Net message from client       922   (마지막) UPDATE T_ORD_STLM SET STLM_AMT = 48200 WHERE STLM_SEQ = 96211
  44       1201     JDBC (정산 WAS)    ACTIVE     enq: TX - row lock contention     402   UPDATE T_ORD_STLM SET STLM_AMT = :1 WHERE STLM_SEQ = :2   (:2 = 96211)
  97       3310     sqlplus (패치)     ACTIVE     enq: TM - contention              388   ALTER TABLE T_ORD_STLM ADD (ADJ_RSN VARCHAR2(100))
    52     1180     JDBC (정산 WAS)    ACTIVE     enq: TM - contention              371   INSERT INTO T_ORD_STLM …
    63     902      JDBC (정산 WAS)    ACTIVE     enq: TM - contention              366   UPDATE T_ORD_STLM SET STLM_AMT = :1 WHERE STLM_SEQ = :2   (:2 = 51077)
    …      (같은 모양 23개 · 모두 BLOCKER 97)
77         402      JDBC (대사 배치)   ACTIVE     db file sequential read             0   UPDATE T_ORD SET PAY_TP = :1, PAY_DT = :2 WHERE ORD_SEQ = :3
  118      5530     JDBC (고객센터)    ACTIVE     enq: TX - row lock contention     214   UPDATE T_ORD SET PAY_TP = :1 WHERE ORD_SEQ = :2
  121      7741     JDBC (고객센터)    ACTIVE     enq: TX - row lock contention      95   UPDATE T_ORD SET PAY_TP = :1 WHERE ORD_SEQ = :2

[트리 밖 — 같은 시각]
88         3001     JDBC (리포트)      ACTIVE     db file sequential read             0   SELECT … FROM T_ORD o JOIN T_ORD_STLM s … (정산 대사 리포트 · 시작한 지 64초)

[V$LOCK — 같은 시각 · 일부]
SID   TYPE  대상 / 이름표          LMODE  REQUEST  BLOCK
131   TM    T_ORD_STLM               3       0       1
131   TX    131 의 트랜잭션           6       0       1
44    TM    T_ORD_STLM               3       0       0
44    TX    131 의 트랜잭션           0       6       0
97    TM    T_ORD_STLM               0       6       0
52    TM    T_ORD_STLM               0       3       0      (63 · 그 밖 23개도 같다)
77    TM    T_ORD                    3       0       0
77    TX    77 의 트랜잭션            6       0       1
118   TX    77 의 트랜잭션            0       6       0      (121 도 같다)
88    (줄 없음)

[V$TRANSACTION — 뿌리 둘]
SID   START_TIME   USED_UBLK   USED_UREC   비고
131   10:26:08          1            2     조민우의 정정 시험 · 저장하지 않고 회의에 들어갔다
77    10:20:01      1,046       52,310     대사 배치 · 3만 건 가운데 약 2만 6천 건째

[88 의 세션 통계 — 시작 뒤 64초]
  consistent gets 412,300 (평소 한 번에 약 38,000) · data blocks consistent reads - undo records applied 371,800 · 기다린 enqueue 0

문제 ​

  1. 블로킹 트리와 V$LOCK을 근거로 사슬을 모두 그리시오. 정정할 행이 96211이 아닌 정산 화면 25개가 왜 멈췄는지, 정산 대사 리포트(88)는 무엇을 기다리는지도 설명하시오.
  2. 지금 할 일을 순서대로 SQL과 함께 쓰시오. 뿌리마다 끊을지 기다릴지와 그 근거(되감을 일의 양)를 쓰시오.
  3. 같은 일이 다시 생기지 않게 할 조치를 셋 이상 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자