Search

[권장:정합+성능]MAX + 1 방식의 채번

BAD

MAX + 1 방식의 채번
SESSION-A
-- 세션A -- 데이터 초기화 (두 세션 실행 전에 완료) TRUNCATE TABLE startdbpg.tr_ord_refund_max; -- 1 BEGIN; -- 2 (번호 1 생성, 아직 커밋하지 않음) INSERT INTO startdbpg.tr_ord_refund_max (refund_req_no ,ord_no ,refund_amt ,refund_reason ,req_st ,req_dtm) SELECT COALESCE(MAX(refund_req_no), 0) + 1 ,1 ,1000 ,'상품 누락 환불' ,'REQ' ,'2024-01-01' FROM startdbpg.tr_ord_refund_max; -- 5 (B가 락 대기 중인 상태에서 커밋) COMMIT;
SQL
복사
SESSION-B
-- 세션B -- 3 BEGIN; -- 4 (동일 번호 1로 INSERT 시도 → 락 대기) INSERT INTO startdbpg.tr_ord_refund_max (refund_req_no ,ord_no ,refund_amt ,refund_reason ,req_st ,req_dtm) SELECT COALESCE(MAX(refund_req_no), 0) + 1 ,1 ,1000 ,'상품 누락 환불' ,'REQ' ,'2024-01-01' FROM startdbpg.tr_ord_refund_max; -- 6 (A의 COMMIT 후 기본키 중복 오류) -- 7 ROLLBACK;
SQL
복사
•
MAX + 1 방식은 동시 실행 시 동일한 번호가 생성되어 기본키 충돌로 인한 락 대기와 중복 오류가 발생할 수 있습니다. 특히 트랜잭션이 길어지면 락 대기 시간이 증가해 동시성이 저하됩니다.

GOOD

시퀀스를 이용한 채번
SESSION-A
-- 세션A -- 데이터 및 시퀀스 초기화 (첫 번째 실행) TRUNCATE TABLE startdbpg.tr_ord_refund_seq RESTART IDENTITY; -- 1 BEGIN; -- 2 (시퀀스로 번호 1 자동 생성) INSERT INTO startdbpg.tr_ord_refund_seq (ord_no ,refund_amt ,refund_reason ,req_st ,req_dtm) VALUES (1 ,1000 ,'상품 누락 환불' ,'REQ' ,'2024-01-01') RETURNING refund_req_no; -- 6 COMMIT;
SQL
복사
SESSION-B
-- 세션B -- 3 BEGIN; -- 4 (A가 커밋하기 전 번호 2 자동 생성) INSERT INTO startdbpg.tr_ord_refund_seq (ord_no ,refund_amt ,refund_reason ,req_st ,req_dtm) VALUES (1 ,1000 ,'상품 누락 환불' ,'REQ' ,'2024-01-01') RETURNING refund_req_no; -- 5 (채번 충돌 없이 정상 커밋) COMMIT;
SQL
복사
•
BIGSERIAL의 시퀀스를 이용해 번호를 자동 생성하여 동시 실행 시 채번 충돌을 방지합니다.
🔎

TIP. 시퀀스를 이용한 자동 채번

•
BIGSERIAL은 시퀀스를 이용해 번호를 자동 생성하는 자료형 선언입니다.
•
시퀀스는 트랜잭션이 롤백되어도 사용한 번호가 복구되지 않으므로 연속된 번호를 보장하지 않습니다.

실행 결과 비교

구분
BAD — MAX + 1
GOOD — BIGSERIAL
SESSION-A 채번 값
1
1
SESSION-B 채번 값
1 시도
2
SESSION-B INSERT
기본키 충돌로 락 대기
정상 처리
SESSION-A COMMIT 이후
SESSION-B 기본키 중복 오류
두 세션 모두 정상 커밋
두 예제는 각각 해당 테이블을 초기화한 다음 독립적으로 실행합니다. SESSION-A의 초기화 SQL을 먼저 완료하고, 주석의 1~7 또는 1~6 순서로 두 세션을 교대로 실행합니다.
💡

KEY POINT

•
동시 실행 가능성이 있는 채번에 MAX() + 1을 사용하지 않습니다. 시퀀스나 IDENTITY 등 동시성을 고려한 채번 방식을 사용합니다.