12화의 장애 뒤에 정산번호를 시퀀스 SQ_STLM_SEQ(CACHE 20)로 바꾼 지 한 달이 지났다. 정산팀 조민우 씨가 빈 번호 목록을 들고 왔다. "6월 첫 주에만 45개가 비었어요. 3일 새벽에는 13개가 한꺼번에요. 데이터가 지워진 건 아니죠?"
개발팀은 아래 DDL을 다음 배포에 넣겠다고 한다. 정산번호의 업무 규정은 12화에서 정한 그대로다. 겹치면 안 되고, 결번은 사유를 기록하면 된다.
[정산팀이 찾은 빈 번호 — 6월 1일 ~ 4일]빈 구간 개수 같은 시각의 기록100412 1 6/1 10:31 앱 로그 · 정산 등록 화면 · 카드사 응답 시간 초과 → ROLLBACK100860 ~ 100889 30 6/2 23:40 배치 로그 · 보정 배치 · 30건째에서 ORA-01400 → 통째로 ROLLBACK101377 ~ 101389 13 6/3 02:10 DBA 작업 대장 · ALTER SYSTEM FLUSH SHARED_POOL (파싱 장애 조치)101902 1 6/4 15:02 앱 로그 · 정산 등록 화면 · 사용자가 저장 중 취소 → ROLLBACK합계 45[DBA_SEQUENCES — 6/5 09:00]SEQUENCE_NAME CACHE_SIZE ORDER_FLAG LAST_NUMBERSQ_STLM_SEQ 20 N 102,341[정산 등록 — 6/1 ~ 6/4] 화면과 배치를 합쳐 초당 최대 4건 · 번호 하나 받기 Buffers 0 (20번에 한 번 SEQ$ 갱신)
-- 제안 DDL 은 넣지 않는다 — SQ_STLM_SEQ 는 CACHE 20, NOORDER 그대로-- 결번 대장 (새로 만든다)CREATE TABLE T_STLM_GAP ( GAP_FROM NUMBER, GAP_TO NUMBER, GAP_CNT NUMBER, FOUND_DT DATE, REASON VARCHAR2(200));-- 매일 08:00 — 지난번에 확인한 번호 뒤부터 빈 구간을 찾는다 (PK 를 범위로 한 번 읽는다)INSERT INTO T_STLM_GAP (GAP_FROM, GAP_TO, GAP_CNT, FOUND_DT)SELECT STLM_SEQ + 1, NXT - 1, NXT - STLM_SEQ - 1, SYSDATE FROM (SELECT STLM_SEQ, LEAD(STLM_SEQ) OVER (ORDER BY STLM_SEQ) AS NXT FROM T_ORD_STLM WHERE STLM_SEQ >= :last_checked_seq) WHERE NXT - STLM_SEQ > 1;COMMIT;-- REASON 은 앱 로그 · 배치 로그 · DBA 작업 대장과 맞춰 채운다 (ROLLBACK · 캐시 소실)
네 구간은 모두 기록으로 설명된다. 100412와 101902는 정산 등록 화면이 번호를 받은 뒤 ROLLBACK한 자리다(카드사 응답 시간 초과, 사용자 취소). 시퀀스는 한 번 나간 번호를 되돌리지 않으므로 ROLLBACK된 번호는 비어서 남는다. 100860 ~ 100889의 30개는 보정 배치가 30건을 등록하다가 ORA-01400으로 통째로 ROLLBACK한 자리다. 101377 ~ 101389의 13개는 6/3 02:10에 공유 풀을 비웠을 때(ALTER SYSTEM FLUSH SHARED_POOL) CACHE 20으로 꺼내 두었던 번호 가운데 아직 쓰지 않은 13개가 사라진 것이다. 따라서 데이터가 지워진 것이 아니다. 지웠다면 그 번호로 등록을 마친 기록이 앱 로그에 있어야 하는데, 네 구간 모두 등록을 마치지 못한 기록뿐이다.
개발팀의 DDL을 넣으면 45개 가운데 캐시 소실로 생긴 13개만 사라진다. ROLLBACK으로 생긴 32개는 NOCACHE로도 막지 못한다. ORDER는 RAC에서 인스턴스끼리 번호 순서를 맞추는 옵션이라 단일 인스턴스에서는 아무것도 바꾸지 않는다. 반면 NOCACHE는 번호마다 딕셔너리 SEQ$를 고치므로(재귀 UPDATE와 redo), 등록이 몰리는 시간에는 enq: SQ - contention 줄이 생긴다. 얻는 것이 작고 대가가 있으므로 넣지 않는다.
대신 결번은 사유를 기록한다는 규정을 지키는 장치를 만든다. 매일 아침 지난번에 확인한 번호 뒤부터 LEAD로 다음 번호와의 차이를 보고, 차이가 1보다 큰 구간을 결번 대장에 넣는다. PK 인덱스를 범위로 한 번 읽으면 되므로 6,214건에 18블록이다. 사유 칸은 앱 로그, 배치 로그, DBA 작업 대장과 맞춰 채운다.