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

가격 한 칸 고치는 상품 화면이 점심때마다 1분씩 멈춘다

중급UPDATE한빛유통512 / 700

상황 ​

12화 포스트모템 뒤 한빛유통도 FK를 하나씩 켜기 시작했다. 6월 3일에 첫 단계로 T_ORD_DET → M_ITM FK를 켰다(고아 0건 확인). 그 주부터 상품팀의 「상품 정보」 화면이 저장 버튼에서 멈춘다. 점심 주문이 몰리는 11:30~13:00에는 평균 41초, 길면 2분 가까이 걸리고, 새벽에는 바로 저장된다. 개발팀은 이렇게 말한다. "가격 한 칸만 바꾸는 UPDATE예요. 키는 건드리지도 않아요." 화면의 SQL은 사내 ORM 프레임워크가 만든다. 엔티티의 컬럼을 전부 SET에 넣는 기본 설정 그대로다.

테이블과 인덱스 ​

  • M_ITM 상품(부모): 100행 · 5블록 · PK_M_ITM (ITM_ID) · 상품팀이 하루 300번쯤 저장한다
  • T_ORD_DET 주문상세(자식): 200,000행 · 896블록 · PK_T_ORD_DET (ORD_SEQ, ORD_DET_NO) · 6월 3일에 켠 FK_ORD_DET_ITM (ITM_ID → M_ITM) ENABLED VALIDATED · ITM_ID가 맨 앞인 인덱스는 없다
  • T_ORD 주문: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ) · 다른 FK는 아직 없다
  • 주문 화면은 T_ORD와 T_ORD_DET를 INSERT한 뒤 결제창이 닫힐 때 COMMIT한다(보통 30초~2분). 점심 피크에는 COMMIT 전 주문이 늘 20~40건 있다.

원본 SQL ​

sql
-- 「상품 정보」 저장: ORM 이 만든 SQL (가격 한 칸만 바꿔도 모양이 같다)
UPDATE M_ITM
   SET ITM_ID  = :1,
       ITM_NM  = :2,
       ITM_TP  = :3,
       UNT_PRC = :4
 WHERE ITM_ID  = :5;
COMMIT;

실행계획 학습용 예시 · 기다림의 모양은 교재 12화 실측(26ai Free) ​

xplan
[「상품 정보」 저장 한 번 — 새벽에 혼자 돌렸을 때]
                              FK 켜기 전    FK 켠 뒤
  session logical reads            3          903      ← T_ORD_DET 896 블록을 통째로 훑는다
  경과                           1 ms        38 ms

[시간표 — 6월 5일 12:10 · 점심 피크 · 상품 1042 의 가격만 바꿨다]
시각       상품 화면 (SID 64)                          주문 화면 (SID 131 · 152 · 177 …)
12:10:00                                               주문 INSERT (T_ORD · T_ORD_DET) · 결제창 — COMMIT 전
12:10:05   저장 → UPDATE M_ITM … → 기다림 (SID 131)
12:10:41                                               SID 131 COMMIT
12:10:41   계속 기다림 (이번엔 SID 152)
12:11:18                                               SID 152 COMMIT · 그다음 SID 177 …
12:11:52   UPDATE 끝 · COMMIT (1분 47초)

[V$SESSION — 12:10:30]
SID   EVENT                            SECS   BLOCKING_SESSION   하고 있는 문장
64    enq: TX - row lock contention      25   131                UPDATE M_ITM SET ITM_ID = :1, ITM_NM = :2 …
131   SQL*Net message from client        30                      (결제창 — 트랜잭션을 연 채)

[V$LOCK — 12:10:30 (TM 은 객체 이름으로)]
SID   TYPE  대상                     LMODE  REQUEST  BLOCK
64    TM    M_ITM                      3      0        0
64    TX    상품 화면의 트랜잭션         6      0        0
64    TX    SID 131 의 트랜잭션          0      4        0      ← 행 락(6)이 아니라 4
131   TM    T_ORD                      3      0        0
131   TM    T_ORD_DET                  3      0        0
131   TM    M_ITM                      3      0        0      ← 자식에 넣은 세션은 부모에도 TM 3
131   TX    SID 131 의 트랜잭션          6      0        1
      (SID 131 이 넣은 주문상세의 상품은 1077 · 1015 — 1042 가 아니다)

[같은 날 「상품 정보」 저장 312 번 — 애플리케이션 로그]
  11:30 ~ 13:00   평균 41초 · 최대 1분 52초        그 밖의 시간   평균 0.04초

문제 ​

  1. 세션 통계와 시간표, V$LOCK을 근거로 가격만 고친 UPDATE가 왜 T_ORD_DET를 통째로 읽고 주문 화면을 기다리는지 설명하시오.
  2. 저장 SQL과 필요한 DDL을 고치시오. 둘 중 하나만 한다면 무엇을 먼저 할지와 그 이유도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자