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

주문번호 중복은 사라졌는데 점심 피크의 결제 저장이 여전히 느리다

중급DDL버거510 / 700

상황 ​

버거원 POS는 지난달 주문번호를 MAX+1에서 시퀀스 SQ_ORD_NO(CACHE 100)로 바꿨다. 주문번호 중복과 다시 시도는 사라졌다. 그런데 점심 피크(11:30 ~ 12:30)에는 결제 저장이 여전히 평균 0.4초이고, 한가한 오후에는 0.02초다. DBA가 피크 한 시간의 AWR과, 기다리는 세션이 가리키는 블록 주소를 뽑아 왔다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_PK (ORD_NO) · ORD_NO는 시퀀스 번호라 늘 지금까지보다 크다
  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · 주문당 평균 2.5행
  • 이 문제의 POS 운영 DB에는 PK 두 개만 있다. ORD_X01 같은 날짜 인덱스는 본사 분석 DB에만 있다
  • ORD_NO를 쓰는 SQL은 모두 등치 조건이다(영수증 재출력 ORD_NO = :no, 주문상품 조회 ORD_ITEM.ORD_NO = :no). V$SQL에서 ORD_NO로 범위를 읽거나 정렬하는 SQL은 찾지 못했다
  • 피크에 동시에 결제를 저장하는 세션은 약 180개다

원본 SQL ​

sql
-- 결제 저장 (지난달 판)
INSERT INTO ORD (ORD_NO, ORD_DT, ORD_HMS, SHOP_NO)
VALUES (SQ_ORD_NO.NEXTVAL, TO_CHAR(SYSDATE, 'YYYYMMDD'), TO_CHAR(SYSDATE, 'HH24MISS'), :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, TO_CHAR(SYSDATE, 'YYYYMMDD'), TO_CHAR(SYSDATE, 'HH24MISS'));
COMMIT;

-- 지금 인덱스
-- ORD_PK      (ORD_NO)            UNIQUE
-- ORD_ITEM_PK (ORD_NO, ITEM_ID)   UNIQUE

실행계획 학습용 예시 · 경합 이벤트의 모양은 교재 12화 실측 ​

xplan
[AWR — 11:30 ~ 12:30 · 결제 54,120건]
Top 대기 이벤트
EVENT                            WAITS     TIME(s)   AVG(ms)   %DB time
buffer busy waits              412,380      2,887         7       41.2
enq: TX - index contention      18,760        938        50       13.4
DB CPU                                      1,712                 24.4
log file sync                   54,300        407         7        5.8
enq: TX - row lock contention        0          0                  0.0

Segments by Buffer Busy Waits
OBJECT        TYPE    BUSY WAITS   %Total
ORD_PK        INDEX      241,230     58.5
ORD_ITEM_PK   INDEX      148,870     36.1
ORD           TABLE       19,790      4.8

[V$SESSION — 12:04:31 · 기다리는 세션 일부]
SID   EVENT                         P1(file#)  P2(block#)  P3(class#)  하는 문장
212   buffer busy waits                     7     183,422           1  INSERT INTO ORD …
305   buffer busy waits                     7     183,422           1  INSERT INTO ORD …
311   buffer busy waits                     7     183,422           1  INSERT INTO ORD …
128   enq: TX - index contention                                       INSERT INTO ORD_ITEM …
247   buffer busy waits                     8      91,077           1  INSERT INTO ORD_ITEM …

[DBA_EXTENTS 로 찾은 블록]
  7 / 183,422   ORD_PK 의 리프 블록 · 지금 맨 오른쪽 리프 (가장 큰 ORD_NO 가 든 블록)
  8 / 91,077    ORD_ITEM_PK 의 리프 블록 · 지금 맨 오른쪽 리프

[인스턴스 통계 · 같은 구간]
  leaf node splits 1,212 · 그중 leaf node 90-10 splits 1,209

문제 ​

  1. AWR과 블록 주소를 근거로 무엇이 무엇을 기다리는지 설명하시오. 행 락과 무엇이 다른지도 쓰시오.
  2. DDL로 고치시오. 그 DDL이 주는 대가와, 이 문제에서 그 대가를 받아들여도 되는 근거를 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자