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

포장 여부 컬럼을 넣는 배포 스크립트가 점심 직전 4분 동안 환불 화면을 세우고 ORA-02296으로 끝났다

중급DDL버거538 / 700

상황 ​

버거 본사는 키오스크의 「포장/매장 식사」 선택을 주문에 남기려고 ORD에 컬럼 하나를 더하기로 했다. 배포 담당자는 개발 DB에서 쓰던 스크립트를 목요일 11:20에 운영에서 돌렸다. 점심 피크는 11:30부터다. 11:20부터 4분 동안 매장 POS의 「환불」 버튼이 돌기만 했다. 결제는 정상이었다. 스크립트는 마지막 줄에서 ORA-02296: cannot enable (DEV.) - null values found로 끝났고, 컬럼은 NULL을 허용한 채 남았다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_PK (ORD_NO) · ORD_X01 (ORD_DT, ORD_HMS) · PCTFREE 10(기본값) · 환불 표시는 상태 칸 ORD_STAT(문제 설정)
  • 점심 전후에는 매장 200곳의 POS가 분당 300건 남짓 주문을 INSERT하고, 환불은 그날 주문을 ORD_NO로 찾아 ORD_STAT을 'R'로 UPDATE한다(하루 수십 건)
  • 운영 DB는 19c다. 개발 DB의 ORD는 1만 행이라 스크립트가 2초 만에 끝났다
  • 새 컬럼은 키오스크와 POS가 값을 넣기 시작할 때까지 'N'(매장 식사)이 기본이다

원본 SQL ​

sql
-- 배포 스크립트 (개발 DB 에서 2초)
ALTER TABLE ORD ADD (TAKEOUT_YN VARCHAR2(1));
UPDATE ORD SET TAKEOUT_YN = 'N';
COMMIT;
ALTER TABLE ORD MODIFY (TAKEOUT_YN DEFAULT 'N' NOT NULL);

실행계획 학습용 예시 ​

xplan
[목요일 — 배포 세션 (SID 66) 과 매장]
시각          배포 (SID 66)                                   매장 POS
11:20:03      ALTER TABLE ORD ADD … (0.02초)
11:20:05      UPDATE ORD SET TAKEOUT_YN = 'N' 시작            결제(INSERT) 정상 · 환불(UPDATE) 하나씩 멈춤
11:24:12      1000000 rows updated (4분 07초) · COMMIT        멈췄던 환불 7건이 한꺼번에 진행
11:24:13      ALTER TABLE ORD MODIFY … NOT NULL
              → ORA-02296: cannot enable (DEV.) - null values found

[UPDATE 한 문장 — ALLSTATS LAST]
----------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |      |      1 |        |      0 |00:04:07.31 |   1043K |
|   1 |  UPDATE            | ORD  |      1 |        |      0 |00:04:07.31 |   1043K |
|   2 |   TABLE ACCESS FULL| ORD  |      1 |   1000K|   1000K|00:00:03.12 |   22422 |
----------------------------------------------------------------------------------
  세션 통계: redo size 268 MB · undo change vector size 96 MB

[V$SESSION — 11:22:00]
SID   EVENT                             SECS   BLOCKING_SESSION   하고 있는 문장
66    db file sequential read              0                      UPDATE ORD SET TAKEOUT_YN = 'N'
141   enq: TX - row lock contention       84   66                 UPDATE ORD SET ORD_STAT = 'R' WHERE ORD_NO = :B1   (매장 SH0117 환불)
187   enq: TX - row lock contention       31   66                 UPDATE ORD SET ORD_STAT = 'R' WHERE ORD_NO = :B1   (매장 SH0042 환불)

[11:30 · 확인]
SELECT COUNT(*) FROM ORD WHERE TAKEOUT_YN IS NULL;   → 1,236   (모두 11:20:05 ~ 11:24:12 에 들어온 주문)

문제 ​

  1. 배포 스크립트의 문장마다 무엇을 잠그고 얼마나 쥐었는지 시간표를 근거로 설명하시오. 결제는 멀쩡했는데 환불만 멈춘 이유와, 마지막 줄이 ORA-02296으로 실패한 이유도 쓰시오.
  2. 같은 컬럼을 기존 행을 하나도 고치지 않고 더하도록 스크립트를 다시 쓰고, 그래도 남는 위험을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자