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

매장 실시간 매출판을 연 뒤로 점심 결제가 서로 다른 매장끼리 줄을 선다

중급DDL버거540 / 700

상황 ​

버거 본사는 이번 달 「매장 실시간 매출판」을 열었다. 결제할 때마다 POS가 SHOP의 그 매장 행에 오늘 결제 건수와 금액을 더한다. 그 뒤로 점심 피크의 결제 완료가 평균 1.6초에서 3.9초로 늘었다. 개발팀은 이렇게 말한다. "매장마다 자기 행만 고치니 락이 걸릴 리가 없어요. POS가 두 대인 매장끼리만 가끔 기다릴 텐데요." DBA가 피크 한 시간의 기록을 뽑아 왔다.

테이블과 인덱스 ​

  • SHOP 매장: 200행 · 5블록 · SHOP_PK (SHOP_NO) · TODAY_CNT와 TODAY_AMT는 원래 있던 컬럼으로, 밤 배치가 하루 한 번 채우던 칸이다
  • 지난달 DBA가 "읽기만 하는 마스터라 빈자리가 아깝다"며 SHOP을 PCTFREE 0으로 MOVE했다. 데이터가 든 블록은 셋이다(블록 1,203 · 1,204 · 1,205에 68 · 68 · 64행). INI_TRANS 1 · 블록마다 ITL 2칸
  • 결제는 주문과 주문상품을 INSERT하고, SHOP 행을 UPDATE한 뒤, 카드 승인 응답(1 ~ 2초)을 받고 COMMIT한다
  • 점심 피크에는 매장 200곳이 분당 300건 남짓 결제한다

원본 SQL ​

sql
-- 결제 저장 (이번 달 판)
INSERT INTO ORD (ORD_NO, ORD_DT, ORD_HMS, SHOP_NO)
VALUES (SQ_ORD_NO.NEXTVAL, :dt, :hms, :shop_no)
RETURNING ORD_NO INTO v_no;
INSERT INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS)
VALUES (v_no, :item_id, :qty, :dt, :hms);                -- 상품마다

UPDATE SHOP                                               -- 실시간 매출판 (이번 달 추가)
   SET TODAY_CNT = TODAY_CNT + 1, TODAY_AMT = TODAY_AMT + :amt
 WHERE SHOP_NO = :shop_no;

-- 카드 승인 응답을 기다린다 (1 ~ 2초)
COMMIT;

-- 지난달 정비
ALTER TABLE SHOP MOVE PCTFREE 0;
ALTER INDEX SHOP_PK REBUILD;

실행계획 학습용 예시 · ITL 대기의 모양은 교재 12화 실측(실습/04 [I1] · [I2]) ​

xplan
[AWR — 점심 11:30 ~ 12:30 · 결제 18,240건]
EVENT                               WAITS     TIME(s)   AVG(ms)   %DB time
enq: TX - allocate ITL entry        6,912     9,815      1,420       61.8
DB CPU                                        2,410                  15.2
enq: TX - row lock contention         214       171        799        1.1
log file sync                      18,300       142          8        0.9

Segments by ITL Waits                  Segments by Row Lock Waits
OBJECT   TYPE    ITL WAITS              OBJECT   TYPE    ROW LOCK WAITS
SHOP     TABLE       6,912              SHOP     TABLE        214

[V$SESSION — 12:04:10 · 기다리는 세션 일부]
SID   EVENT                            SECS   BLOCKING_SESSION   하는 문장                            고치는 매장   행이 든 블록
305   enq: TX - allocate ITL entry        1   212                UPDATE SHOP … WHERE SHOP_NO = :B1    SH0031       7 / 1,203
318   enq: TX - allocate ITL entry        1   212                UPDATE SHOP …                        SH0057       7 / 1,203
412   enq: TX - allocate ITL entry        2   190                UPDATE SHOP …                        SH0140       7 / 1,205
(212 는 SH0012 · 블록 1,203 · 190 은 SH0161 · 블록 1,205 — 둘 다 카드 승인 응답을 기다리는 중 · SQL*Net message from client)

[V$LOCK — 같은 시각 · 305 와 212]
SID   TYPE  대상 / 이름표       LMODE  REQUEST  BLOCK
305   TM    SHOP                  3       0       0
305   TX    212 의 트랜잭션        0       4       0
212   TM    SHOP                  3       0       0
212   TX    212 의 트랜잭션        6       0       1

[DBA_TABLES · SHOP]   PCT_FREE 0 · INI_TRANS 1 · 데이터 블록 3 · 블록마다 빈자리 거의 0

문제 ​

  1. AWR과 V$SESSION, V$LOCK을 근거로 서로 다른 매장의 결제가 무엇을 기다리는지 설명하시오. 행 락 대기와 어떻게 다른지도 쓰시오.
  2. DDL로 고치시오. ALTER TABLE SHOP INITRANS 16 한 줄로는 왜 안 되는지와 그 DDL의 대가도 쓰시오.
  3. 결제 쪽 SQL에서 줄을 더 줄일 방법을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자