PostgreSQL 기본 키를 위한 최적의 UUID 유형 선택
Olivia Novak
Dev Intern · Leapcell

소개
현대 데이터베이스 설계의 끊임없이 진화하는 환경에서 적절한 기본 키 전략을 선택하는 것은 매우 중요합니다. 전통적인 자동 증가 정수가 오랫동안 기본값이었지만, 분산 시스템, 마이크로서비스 아키텍처, 데이터 샤딩의 요구 사항은 종종 더 전역적으로 고유한 식별자를 필요로 합니다. 보편적으로 고유한 식별자(UUID)는 키 생성을 위한 분산형 접근 방식을 제공하는 강력한 대안으로 부상했습니다. 그러나 UUID 표준 자체는 각기 다른 속성을 가진 여러 변형을 제공합니다. 이 기사는 PostgreSQL에서 기본 키로서의 적합성을 평가하는 세 가지 두드러진 UUID 버전—v1, v4, v7—을 깊이 파고듭니다. 기본 메커니즘을 탐구하고, 실제적 영향을 논의하며, 궁극적으로 데이터베이스에 가장 유리한 선택을 안내할 것입니다.
UUID 해독: 핵심 개념 이해
각 UUID 버전을 자세히 살펴보기 전에, UUID가 무엇인지, 그리고 기본 키로서 성능에 영향을 미치는 주요 특성에 대한 기본적인 이해를 확립해 봅시다.
A UUID는 컴퓨터 시스템에서 정보를 고유하게 식별하는 데 사용되는 128비트 숫자입니다. 텍스트로 렌더링될 때, 일반적으로 하이픈으로 구분된 32개의 16진수 숫자 문자열로 표현됩니다(예: 123e4567-e89b-12d3-a456-426614174000). ISO/IEC 9834-8:2005 및 RFC 4122 표준은 서로 다른 생성 알고리즘을 가진 여러 버전을 정의합니다.
기본 키의 경우 몇 가지 요소가 중요합니다.
- 고유성: 주요 요구 사항입니다. UUID는 충돌 위험을 거의 제거하는 전역적으로 고유하도록 설계되었습니다.
 - 삽입 성능: 새 레코드를 얼마나 빨리 추가할 수 있는지입니다. 이는 인덱스 구조와 쓰기 패턴에 의해 크게 영향을 받습니다.
 - 쿼리 성능: 레코드를 얼마나 효율적으로 검색할 수 있는지입니다. 다시 말하지만, 인덱스 구조가 중요한 역할을 합니다.
 - 저장 효율성: 기본 키 자체와 관련 인덱스가 소비하는 공간입니다.
 - 클러스터링 계수: B-트리 인덱스의 경우, 좋은 클러스터링 계수(물리적으로 인접한 행이 인덱스에서 논리적으로 인접한 경우)는 더 나은 캐싱과 더 적은 디스크 I/O를 초래합니다.
 - 단조성/시간 정렬 가능성: 생성된 키가 시간이 지남에 따라 증가하는 경향이 있는지 여부입니다. 이는 범위 쿼리 및 인덱스 성능에 유익합니다.
 
이제 각 UUID 버전을 살펴보겠습니다.
UUID v1: 시간 기반 및 MAC 주소 종속
UUID v1은 현재 타임스탬프와 이를 생성하는 호스트의 MAC 주소를 결합합니다.
- 생성: 60비트 타임스탬프(1582년 10월 15일 이후 100나노초 간격의 수)와 48비트 MAC 주소를 사용합니다. 클럭 조정 및 MAC 주소를 사용할 수 없을 때 고유성을 보장하기 위해 클럭 시퀀스 필드가 추가됩니다.
 - 특성:
- 시간 순서: 일반적으로 나중에 생성된 v1 UUID는 이전에 생성된 UUID보다 수치적으로 큽니다. 이 속성은 새 삽입이 종종 순차적으로 추가되어 페이지 분할을 줄이고 블록 캐싱을 개선하므로 B-트리 인덱스에 유리합니다.
 - 전역 고유성: 타임스탬프와 MAC 주소로 인해 매우 고유합니다.
 - 정보 노출: 생성된 머신의 MAC 주소를 노출하는데, 이는 개인 정보 보호 문제가 될 수 있습니다.
 - 이식성 문제: MAC 주소에 의존하는 것은 MAC 주소가 변경되거나 무작위화될 수 있는 가상화 또는 클라우드 환경에서 문제가 될 수 있습니다.
 
 
예시 (PostgreSQL):
SELECT uuid_generate_v1(); -- 예시 출력: 'a1b2c3d4-e5f6-11e9-8765-1234567890ab'
(참고: uuid_generate_v1()은 PostgreSQL에서 uuid-ossp 확장을 활성화해야 합니다.)
UUID v4: 무작위성이 지배
UUID v4는 순전히 무작위 또는 의사 무작위 숫자를 통해 생성됩니다.
- 생성: 122비트가 무작위로 생성되며, 특정 비트는 v4 UUID로 식별하기 위해 예약됩니다.
 - 특성:
- 정보 노출 없음: 생성된 호스트 또는 시간에 대한 식별 가능한 정보가 포함되어 있지 않습니다.
 - 높은 고유성: 충분히 좋은 난수 생성기를 가정합니다. 충돌 확률은 극히 낮습니다.
 - 나쁜 삽입 성능: v4 UUID는 무작위이므로, 새 기본 키는 전체 인덱스 범위에 걸쳐 분산됩니다. 이는 빈번한 인덱스 페이지 분할, 증가된 I/O 작업, 더 높은 캐시 누락, 그리고 나쁜 클러스터링 계수로 이어집니다. 이는 특히 트래픽이 많은 테이블에서 삽입 성능을 크게 저하시킬 수 있습니다.
 - 무작위 액세스 패턴: v4 UUID로 쿼리하는 것은 인덱스 내에서 무작위 액세스를 포함하는데, 이는 일반적으로 순차 액세스보다 덜 효율적입니다.
 
 
예시 (PostgreSQL):
SELECT gen_random_uuid(); -- 예시 출력: 'f8d7e6c5-b4a3-4210-90fe-fedcb9876543'
(참고: gen_random_uuid()는 PostgreSQL 13부터 내장되어 있습니다. 이전 버전에서는 uuid-ossp의 uuid_generate_v4()가 동일한 목적을 수행합니다.)
UUID v7: 두 세계의 최고?
UUID v7은 초안 RFC(최신은 RFC 9562)에 정의된 새로운 표준으로, 시간 정렬성과 무작위성을 결합하여 v1 및 v4의 단점을 해결하는 것을 목표로 합니다.
- 생성: 48비트 Unix epoch 타임스탬프(밀리초 단위)로 시작하며, 버전 및 변형을 위한 12비트, 그리고 62비트의 의사 무작위 데이터가 이어집니다. 이 시간 구성 요소는 자연스럽게 정렬 가능하게 만듭니다.
 - 특성:
- 시간 정렬: 선행 타임스탬프는 새 UUID가 이전 UUID보다 수치적으로 큰 경향이 있도록 보장합니다. 이는 B-트리 인덱스에서 삽입 성능을 크게 향상시키며, 페이지 분할을 최소화하고 좋은 클러스터링 계수를 유지하여 자동 증가 정수와 유사합니다.
 - 정보 노출 없음: v1과 달리 MAC 주소를 포함하지 않아 개인 정보를 보호합니다.
 - 높은 고유성: 무작위 구성 요소는 강력한 고유성 보장을 제공합니다.
 - 데이터베이스 친화적: 특히 데이터베이스 인덱스 성능을 염두에 두고 설계되었습니다.
 - 표준화: 신흥 표준이지만, 빠르게 채택되고 있습니다.
 
 
예시 (개념적/uuid_v7 확장으로 추정):
작성 시점에 gen_random_uuid() 또는 uuid-ossp는 코어 PostgreSQL에서 v7 생성을 직접 제공하지 않습니다. 그러나 사용자 정의 함수 또는 확장(예: uuid_v7 커뮤니티 확장)이 이를 구현할 수 있습니다.
-- 사용자 정의 함수 또는 확장 'uuid_generate_v7()'이 있다고 가정 SELECT uuid_generate_v7(); -- 예시 출력: '018b3687-3400-7bb0-b747-d16c527e7f8a' -- 선행 부분은 시간 기반임을 주목하세요.
PostgreSQL의 uuid 데이터 유형 및 성능
PostgreSQL은 16바이트 값으로 UUID를 효율적으로 저장하는 네이티브 uuid 데이터 유형을 가지고 있습니다. 이는 텍스트로 저장하는 것보다 훨씬 좋습니다. 텍스트는 가변 바이트(문자열 표현의 경우 일반적으로 36바이트)를 소비하고 인덱싱 및 비교 중에 변환이 필요합니다.
UUID를 기본 키로 사용할 때, PostgreSQL은 해당 열에 B-트리 인덱스를 생성합니다. 위에 논의된 성능 영향(삽입 속도, 클러스터링 계수)은 UUID 생성 패턴이 B-트리 인덱스 특성과 얼마나 잘 일치하는지와 직접적으로 관련됩니다.
권장 사항: UUID v7의 경우
분석을 고려할 때, UUID v7은 PostgreSQL에서 기본 키에 대한 우수한 선택입니다.
이유는 다음과 같습니다.
- B-트리 인덱스에 최적화됨: 시간 정렬된 접두사는 새 항목이 대부분 인덱스의 "끝"에 추가되도록 보장합니다. 이는 무작위 쓰기를 최소화하고, 인덱스 페이지 분할을 줄이며, 인덱스를 컴팩트하게 유지하고, 높은 클러스링 계수를 유지합니다. 결과적으로 v4에 비해 삽입 성능이 훨씬 뛰어나고 I/O 오버헤드가 줄어듭니다.
 - 타협 없는 전역 고유성: MAC 주소 노출(v1과 같은)의 개인 정보 보호 문제나 시퀀스 조정의 운영 복잡성 없이 무작위 구성을 통해 강력한 전역 고유성을 제공합니다.
 - 분산 시스템에서의 확장성: 기본 키가 여러 노드에서 중앙 조정 없이 독립적으로 생성되어야 하지만, 관계형 데이터베이스에서 여전히 잘 수행되어야 하는 분산 환경에 이상적입니다.
 - 정보 노출 없음: v1과 달리 생성된 호스트에 대한 세부 정보를 공개하지 않습니다.
 
v1은 시간 정렬 기능을 제공하지만, MAC 주소에 대한 의존성과 잠재적인 개인 정보 보호 문제는 이를 덜 매력적으로 만듭니다. UUID v4는 단순함에도 불구하고, 완전히 무작위적인 특성으로 인해 광범위한 인덱스 변경을 유발하는 대형, 쓰기 집약적인 테이블의 기본 키에 대한 알려진 성능 병목 현상입니다.
v7을 직접 사용할 수 없는 경우(예: 확장 기능이 없는 이전 PostgreSQL 버전), reasonable 대안은 UUID v4를 생성하여 BYTEA 열에 저장하거나, 타임스탬프가 의도적으로 처음에 배치된 "COMB"(결합된 시간 정렬) UUID 접근 방식을 사용하는 것입니다. 그러나 표준화된 v7 구현을 직접 활용하는 것이 가장 깨끗하고 미래 지향적인 솔루션입니다.
결론
PostgreSQL 기본 키에 대한 올바른 UUID 변형을 선택하는 것은 데이터베이스 성능, 확장성 및 유지 관리성에 깊은 영향을 미칩니다. UUID v1은 시간 정렬을 제공하고 v4는 순수한 무작위성을 제공하지만, UUID v7은 최적의 균형을 이룹니다. 선행 타임스탬프와 강력한 무작위 구성 요소를 결합함으로써, UUID v7은 두 세계의 장점을 제공합니다. 즉, 강력한 전역 고유성과 함께 높은 볼륨의 쓰기에 필수적인 매우 효율적인 인덱스 성능입니다. 최신 PostgreSQL 애플리케이션의 경우, UUID v7은 궁극적인 기본 키 선택으로 두드러집니다.