빠른 비교
| 방식 | 형태 | 기준 |
|---|---|---|
IDENTITY | 표준 SQL 자동 증가 | 새 스키마에서 우선 검토 |
SERIAL | sequence + default 축약 | 기존 PostgreSQL 관용 |
| 직접 sequence | 별도 번호 생성기 | 여러 테이블 공유나 특수 제어 |
CREATE TABLE users (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
email TEXT NOT NULL UNIQUE
);문법
IDENTITY는 컬럼 정의 안에 자동 증가 규칙을 명시한다
GENERATED ... AS IDENTITY는 자동 증가 컬럼을 표준 SQL에 가까운 형태로 선언합니다. BY DEFAULT는 명시 값을 넣을 수 있고, ALWAYS는 기본적으로 사용자가 값을 직접 넣지 못하게 합니다.
CREATE TABLE orders (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id BIGINT NOT NULL
);마이그레이션이나 외부 데이터 복원처럼 기존 ID를 그대로 넣어야 하는 경우가 있으면 BY DEFAULT가 유연합니다. 반대로 애플리케이션이 ID를 직접 지정하면 안 되는 규칙을 강하게 두려면 ALWAYS가 더 명확합니다.
SERIAL은 sequence와 DEFAULT를 자동으로 만든다
BIGSERIAL은 실제 자료형이 아니라 BIGINT 컬럼, sequence, DEFAULT nextval(...)를 함께 만드는 축약 문법입니다. 기존 PostgreSQL 코드베이스에서 매우 흔하게 쓰입니다.
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL
);대략 아래처럼 해석할 수 있습니다.
CREATE SEQUENCE posts_id_seq;
CREATE TABLE posts (
id BIGINT NOT NULL DEFAULT nextval('posts_id_seq') PRIMARY KEY,
title TEXT NOT NULL
);Sequence 동작
sequence는 트랜잭션 롤백과 별도로 증가합니다. nextval()로 값을 받은 뒤 트랜잭션이 실패해도 그 번호는 되돌아가지 않습니다. 그래서 자동 증가 ID에는 gap이 생길 수 있습니다.
SELECT nextval('orders_id_seq');
SELECT currval('orders_id_seq');gap 없는 번호가 회계 전표나 송장 번호처럼 비즈니스 규칙이면 일반 PK sequence로 해결하면 안 됩니다. 별도 잠금, 번호 발급 테이블, 발급 확정 시점 설계가 필요합니다.
재시작과 동기화
수동으로 ID를 넣었거나 데이터를 복원한 뒤 sequence 현재값이 실제 최댓값보다 낮으면 다음 INSERT에서 중복 키 오류가 날 수 있습니다. 이때는 sequence 값을 테이블 최댓값에 맞춥니다.
SELECT setval(
'users_id_seq',
(SELECT COALESCE(MAX(id), 0) FROM users)
);주의할 점
자동 증가 ID는 순서를 보장하는 업무 번호가 아닙니다. 트랜잭션 실패, 캐시, 동시 실행 때문에 번호가 건너뛸 수 있습니다.
또 dump/restore, 수동 INSERT, 데이터 이관 후에는 sequence 현재값과 테이블의 실제 최댓값이 어긋날 수 있습니다. 중복 키 오류가 나면 sequence 동기화 여부를 먼저 확인하세요.
참고 링크
2 sources