핵심 요약
기본키(PK)로 자동증가 정수(1, 2, 3...)를 쓸지 UUID(랜덤한 긴 문자열)를 쓸지는 흔한 고민이다. 정수는 작고 빠르고 인덱스에 유리하지만 예측 가능하고 여러 DB를 합칠 때 충돌한다. UUID는 어디서 만들어도 겹칠 걱정이 없지만 크고 랜덤이라 인덱스 성능에 불리하다.
1. 비교
| 항목 | 자동증가 정수 | UUID |
|---|---|---|
| 크기 | 4~8바이트(작음) | 16바이트(2~4배) |
| 생성 위치 | DB가 채번 | 앱·어디서든 가능 |
| 예측 가능성 | 높음(보안 우려) | 사실상 불가 |
| 분산/병합 | 충돌 위험 | 안전 |
| 인덱스 | 순차라 유리 | 랜덤이라 불리 |
2. 자동증가의 문제 — 예측 가능성
/users/1, /orders/1002처럼 순차 ID를 URL에 노출하면, 남의 리소스를 번호만 바꿔 추측할 수 있다(IDOR 취약점의 단초). 또 "총 사용자 수"가 ID로 유추된다. 외부에 노출되는 식별자로는 위험하다.
3. UUID의 문제 — 인덱스 성능
완전 랜덤 UUID(v4)는 값이 여기저기 흩어져, 삽입할 때마다 B-Tree 인덱스의 아무 데나 끼어들어 페이지가 조각난다. 그래서 대량 삽입이 느려질 수 있다. 이를 해결한 게 UUIDv7 — 시간 순서를 앞에 담아 대체로 순차적이라 인덱스 친화적이다.
4. 실무 선택
- 내부 전용·단일 DB → 자동증가 정수로 충분(간단·빠름)
- 외부 노출·분산·병합 필요 → UUID(가급적 v7)
- 절충안 — 내부 PK는 정수, 외부 노출용은 별도 UUID·짧은 랜덤 문자열(예:
ULID, nanoid)을 둔다. 많은 서비스가 이 방식을 쓴다.
자주 묻는 질문
그냥 자동증가 정수 쓰면 안 되나요?
내부용이고 DB가 하나면 충분합니다. 다만 그 ID를 URL·API로 외부에 노출한다면 예측 가능성 문제가 있으니, 노출용 식별자만 랜덤(UUID/ULID)으로 분리하는 걸 고려하세요.
UUIDv4와 v7 차이가 뭔가요?
v4는 완전 랜덤이라 인덱스에 흩어져 삽입 성능이 떨어집니다. v7은 앞부분에 타임스탬프를 담아 대체로 시간순으로 증가하므로, UUID의 장점(전역 유일성)을 유지하면서 인덱스 성능 문제를 크게 줄입니다. 새로 UUID를 도입한다면 v7이 유리합니다.
UUID를 문자열로 저장해도 되나요?
가능하지만 비효율적입니다. 36자 문자열로 저장하면 16바이트 바이너리보다 2배 이상 공간을 쓰고 인덱스도 커집니다. DB가 UUID 전용 타입(또는 바이너리 저장)을 지원하면 그걸 쓰는 게 좋습니다.

댓글 0