테마
한빛유통 콜센터의 「결제 수단 변경」 화면은 결제 전(PENDING) 주문의 결제 수단을 바꾼다. 지난달 개발팀은 동시 수정으로 변경이 사라지는 일을 막으려고 낙관적 잠금을 넣었다. 테이블은 고치지 않고, 주문을 열 때 ORA_ROWSCN을 함께 읽어 두었다가 저장할 때 비교한다.
반영 다음 날부터 상담원들의 불만이 쏟아졌다. "아무도 안 건드린 주문인데 저장하면 '다른 사용자가 먼저 수정했습니다'가 떠요. 다시 열고 저장하면 또 떠요."
T_ORD 주문: 100,000행 · 896블록(블록 하나에 약 112행) · PK_T_ORD (ORD_SEQ) · 만들 때 옵션을 주지 않았다(기본값 NOROWDEPENDENCIES)ORD_ST, PAY_DT를 하루 약 46,000번 고치고 바로 COMMIT한다. 최근 주문은 테이블 끝쪽 블록에 모여 있다.-- 주문 열기
SELECT ORD_SEQ, CUS_ID, ORD_ST, PAY_TP, ORD_AMT, ORA_ROWSCN AS ROW_SCN
FROM T_ORD
WHERE ORD_SEQ = :ord_seq;
-- 저장 — 연 뒤로 아무도 안 고쳤을 때만 (0행이면 "다른 사용자가 먼저 수정했습니다")
UPDATE T_ORD
SET PAY_TP = :pay_tp
WHERE ORD_SEQ = :ord_seq
AND ORA_ROWSCN = :row_scn;
COMMIT;
[저장 실패 한 건 — 주문 98,214 (PENDING)]
14:20:03 주문 열기 → ROW_SCN 48,213,907
14:21:40 저장 → UPDATE 0행 → "다른 사용자가 먼저 수정했습니다"
그 사이 주문 98,214 를 고친 트랜잭션: 없음 (감사 로그)
같은 블록의 다른 주문을 고친 결제 콜백: 9번 (14:20:11 ~ 14:21:33)
[같은 블록의 행 — 14:21:40]
SELECT ORD_SEQ, ORD_ST, ORA_ROWSCN, DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) AS BLK
FROM T_ORD WHERE ORD_SEQ BETWEEN 98201 AND 98312;
ORD_SEQ ORD_ST ORA_ROWSCN BLK
98,201 COMPLETE 48,214,566 1183
98,202 COMPLETE 48,214,566 1183
…
98,214 PENDING 48,214,566 1183 ← 14:20 이후 아무도 고치지 않았다
…
98,312 COMPLETE 48,214,566 1183 (112행 모두 같은 값)
[저장 UPDATE — ALLSTATS LAST (0행)]
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | | 0 | 00:00:00.01 | 3 |
| 1 | UPDATE | T_ORD | 1 | | 0 | 00:00:00.01 | 3 |
|* 2 | TABLE ACCESS BY INDEX ROWID | T_ORD | 1 | 1 | 0 | 00:00:00.01 | 3 |
|* 3 | INDEX UNIQUE SCAN | PK_T_ORD | 1 | 1 | 1 | 00:00:00.01 | 2 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ORA_ROWSCN"=:ROW_SCN)
3 - access("ORD_SEQ"=:ORD_SEQ)
[반영 뒤 일주일] 저장 1,920번 · 0행 실패 604번 (31%) · 실제로 다른 사람이 같은 주문을 고친 경우 3번
ORA_ROWSCN의 성질과 위의 조회 결과로 설명하시오.