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

매장 리포트를 빠르게 했다는 다음 날 점심, POS 결제가 수십 초씩 멈춘다

중급INSERT버거518 / 700

상황 ​

버거 본사 BI팀은 월요일 밤 「매장별 일 매출」 리포트를 빠르게 하려고 ORD에 인덱스 두 개를 만들었다(리포트 22,422 → 380블록). 화요일 11:50부터 전국 매장 POS의 결제 완료가 수십 초씩 걸렸고, 점장들의 전화가 본사로 몰렸다. 운영팀은 "DB CPU는 20%라 한가하다"고 했다. POS는 결제 버튼을 누르면 주문과 주문상품을 넣고, 카드 승인 응답을 받은 뒤 COMMIT한다(보통 1~2초). 점심 피크에는 매장 200곳이 1분에 300건 남짓 결제한다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_NO NUMBER · ORD_DT VARCHAR2(8) · SHOP_NO VARCHAR2(10) ('SH0001' ~ 'SH0200') · ORD_PK (ORD_NO) · ORD_X01 (ORD_DT, ORD_HMS)
  • 월요일 밤 BI팀이 만든 인덱스: ORD_BX01 BITMAP (ORD_DT) · ORD_BX02 BITMAP (SHOP_NO)
  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS) (비트맵 없음)
  • 리포트는 하루 두 번(09:00, 18:00) 본사에서 돈다. 지역 매장 묶음(5~20곳)과 기간(한 달)으로 매장별 일 주문 건수를 센다. 매장 하나의 하루 주문은 7건 안팎이다.

원본 SQL ​

sql
-- POS 결제 (매장 200곳 · 계산대마다)
INSERT INTO ORD (ORD_NO, ORD_DT, ORD_HMS, SHOP_NO)
VALUES (:ord_no, TO_CHAR(SYSDATE, 'YYYYMMDD'), TO_CHAR(SYSDATE, 'HH24MISS'), :shop_no);
INSERT INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS)
VALUES (:ord_no, :item_id, :qty, TO_CHAR(SYSDATE, 'YYYYMMDD'), TO_CHAR(SYSDATE, 'HH24MISS'));   -- 상품마다
-- 카드 승인 응답을 기다린다 (1 ~ 2초)
COMMIT;

-- 「매장별 일 매출」 리포트 (하루 두 번)
SELECT o.SHOP_NO, o.ORD_DT, COUNT(*) AS ord_cnt
  FROM ORD o
 WHERE o.SHOP_NO IN (:s1, :s2, :s3, :s4, :s5)
   AND o.ORD_DT BETWEEN :from_dt AND :to_dt
 GROUP BY o.SHOP_NO, o.ORD_DT;

-- 월요일 밤 BI 팀
CREATE BITMAP INDEX ORD_BX01 ON ORD (ORD_DT);
CREATE BITMAP INDEX ORD_BX02 ON ORD (SHOP_NO);

실행계획 학습용 예시 · ASH 읽는 법은 교재 17화 ​

xplan
[ASH — 화요일 11:50 ~ 12:20 · 상위 이벤트]
EVENT                              표본     %     SQL
enq: TX - row lock contention      4,812   81%   INSERT INTO ORD (ORD_NO, ORD_DT, ORD_HMS, SHOP_NO) VALUES (:1, …)
CPU                                  702   12%
log file sync                        298    5%
(INSERT INTO ORD_ITEM 의 enq: TX 표본은 0 이다)

[V$LOCK — 12:05:12 · POS 세션 일부]
SID   TYPE  대상                   LMODE  REQUEST  BLOCK
407   TM    ORD                      3      0        0
407   TX    SID 407 의 트랜잭션        6      0        1      ← SH0081 · 카드 승인 응답을 기다리는 중 (COMMIT 전)
512   TX    SID 407 의 트랜잭션        0      4        0      ← SH0117 의 주문
388   TX    SID 407 의 트랜잭션        0      4        0      ← SH0042 의 주문
611   TX    SID 512 의 트랜잭션        0      4        0      ← SH0117 의 다른 계산대
      … REQUEST 4 로 기다리는 POS 세션 41개

[POS 결제 한 건 — 점심 피크]
  지난주 화요일   평균 1.4초 (거의 카드 승인)
  이번 화요일     평균 23초 · 최대 71초 · 결제 포기(타임아웃 60초) 186건

[리포트 — BI팀의 측정]  인덱스 전 TABLE ACCESS FULL 22,422블록 → 인덱스 뒤 BITMAP AND · 380블록

문제 ​

  1. ASH와 V$LOCK을 근거로 서로 다른 매장의 주문 INSERT가 왜 한 줄로 서는지 설명하시오. ORD_ITEM INSERT는 왜 기다리지 않는지도 쓰시오.
  2. POS가 기다리지 않게 고치고, 리포트를 위한 인덱스를 다시 설계하시오. 그 인덱스의 대가도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자