목록으로
유틸리티

UUID 총정리, 버전 1부터 7까지 차이점과 선택 기준 5가지

UUID 총정리가 필요한 순간은 대체로 비슷합니다. 여러 서버에서 중복 없는 식별자를 만들어야 하는데, 버전이 1부터 8까지 나뉘어 있고 각각 무엇이 다른지 한곳에 정리된 자료를 찾기 어려울 때입니다. 이 글에서는 UUID의 내부 구조부터 버전별 차이, 데이터베이스 저장 전략, 실무에서 반복되는 함정까지 순서대로 살펴봅니다.

UUID의 구조와 128비트 구성

UUID는 Universally Unique Identifier의 약자로, 128비트 길이의 식별자입니다. 사람이 읽는 형태로는 16진수 32자를 8-4-4-4-12로 끊어 표기하며, 하이픈까지 포함하면 총 36자가 됩니다.

예를 들어 550e8400-e29b-41d4-a716-446655440000 같은 값입니다. 언뜻 전부 무작위로 보이지만, 사실 자리마다 의미가 정해져 있습니다.

  • 세 번째 그룹의 첫 글자는 버전 번호입니다. 위 예시는 4이므로 UUIDv4입니다.
  • 네 번째 그룹의 첫 글자는 variant 값으로, RFC 표준을 따르면 8, 9, a, b 중 하나가 옵니다.
  • 버전과 variant를 표시하는 6비트를 제외한 나머지가 실제 고유성을 담당합니다. v4의 경우 122비트가 난수입니다.

122비트 난수는 대략 5.3 곱하기 10의 36제곱 가지 경우의 수를 갖습니다. 초당 10억 개씩 100년간 생성해도 충돌 확률이 사실상 무시할 수준이라, 중앙 채번 서버 없이도 각 노드가 독립적으로 키를 만들 수 있다는 것이 UUID의 핵심 가치입니다.

참고: UUID 표준은 2024년 RFC 9562로 개정되며 기존 RFC 4122를 대체했습니다. 이 개정에서 v6, v7, v8이 정식 표준으로 편입되었습니다.

버전별 차이점 한눈에 비교

버전 번호는 우열이 아니라 생성 방식의 분류입니다. 숫자가 크다고 더 안전하거나 더 고유한 것은 아닙니다.

버전생성 방식시간순 정렬주요 용도
v1타임스탬프 + MAC 주소부분적레거시 시스템
v3네임스페이스 + MD5불가결정적 식별자
v4난수 122비트불가범용, 가장 널리 사용
v5네임스페이스 + SHA-1불가결정적 식별자, v3보다 권장
v6v1의 비트 순서 재배열가능v1 사용처의 이전 경로
v7유닉스 밀리초 + 난수가능데이터베이스 기본키
v8구현체가 자유 정의설계에 따름사내 커스텀 규칙

v3과 v5는 성격이 조금 다릅니다. 같은 네임스페이스와 같은 이름을 넣으면 언제 어디서 실행하든 항상 동일한 UUID가 나옵니다. 외부 시스템의 문자열 키를 UUID 형태로 안정적으로 매핑해야 할 때 유용합니다. 반대로 말하면 값이 예측 가능하므로 보안 토큰으로는 절대 쓰면 안 됩니다.

식별자를 고를 때 먼저 던져야 할 질문은 얼마나 고유한가가 아니라, 시간순으로 정렬되어야 하는가입니다.

UUIDv4와 UUIDv7의 데이터베이스 성능 차이

실무에서 실제로 저울질하게 되는 선택지는 v4와 v7 두 가지입니다. 둘의 차이는 인덱스에서 드러납니다.

대부분의 관계형 데이터베이스는 기본키를 B-tree 인덱스로 관리합니다. 새로 들어오는 키 값이 항상 마지막 페이지 뒤에 붙으면 삽입 비용이 낮지만, v4처럼 완전히 무작위인 값은 인덱스 중간 아무 곳에나 꽂힙니다. 그 결과 페이지 분할이 잦아지고, 인덱스가 커질수록 버퍼 캐시 적중률이 떨어지며, 테이블이 수백만 행 규모가 되면 삽입 성능이 눈에 띄게 저하됩니다.

UUIDv7은 앞쪽 48비트에 유닉스 밀리초 타임스탬프를 넣고 나머지를 난수로 채웁니다. 문자열로 정렬해도 생성 순서가 유지되므로 삽입이 인덱스 오른쪽 끝에 몰리고, 자동 증가 정수형에 가까운 삽입 패턴을 얻으면서도 분산 생성이라는 장점은 그대로 유지됩니다.

주의: UUIDv7은 생성 시각이 값에 그대로 담깁니다. 가입자 수나 주문 발생 시점을 외부에 노출하고 싶지 않은 공개 URL에는 v7을 그대로 쓰지 말고, 별도의 v4 값이나 난수 슬러그를 외부 식별자로 두는 편이 안전합니다.

실무에서 놓치기 쉬운 5가지

  1. 저장 타입 선택. MySQL에서 UUID를 CHAR(36)으로 저장하면 36바이트를 쓰지만 BINARY(16)은 16바이트면 충분합니다. 인덱스 크기가 절반 이하로 줄어드는 만큼 조회 성능도 달라집니다. PostgreSQL은 전용 uuid 타입을 제공하므로 그대로 쓰면 됩니다.
  2. 보안과 고유성의 혼동. UUID는 충돌 방지를 위한 규격이지 비밀 유지를 위한 규격이 아닙니다. 비밀번호 재설정 링크나 세션 토큰에는 암호학적 난수 생성기 기반의 값을 별도로 쓰는 것이 원칙입니다.
  3. 대소문자 처리. 표준 표기는 소문자이지만 일부 언어와 데이터베이스는 대문자를 반환합니다. 문자열로 비교하는 코드가 있다면 저장 시점에 한쪽으로 정규화해 두어야 합니다.
  4. 하이픈 제거 여부. 하이픈을 뺀 32자 형태와 36자 형태가 시스템마다 섞이면 조회 실패가 생깁니다. 경계에서 한 번만 변환하고 내부는 한 가지 형태로 통일하는 것이 안전합니다. 값 몇 개를 즉석에서 뽑아 테스트 데이터로 쓰거나 형식을 눈으로 확인하고 싶을 때는 UUID 생성기를 활용하면 편리합니다.
  5. 정렬 기준 오해. v4는 정렬해도 아무 의미가 없습니다. 생성 순서가 필요하면 별도의 created_at 컬럼을 두거나 처음부터 v7을 선택해야 합니다.
팁: 기존 v4 기반 테이블을 v7로 바꿀 때 전체 데이터를 마이그레이션할 필요는 없습니다. 두 값 모두 128비트이고 버전 비트만 다르므로, 신규 행부터 v7로 발급해도 기존 행과 같은 컬럼에 공존할 수 있습니다.

환경별 생성 방법

별도 라이브러리 없이 표준 기능만으로 생성할 수 있는 경우가 많습니다.

  • 브라우저와 Node.js 18 이상: crypto.randomUUID()로 v4를 반환합니다. 브라우저에서는 HTTPS 같은 보안 컨텍스트에서만 동작합니다.
  • Python: import uuiduuid.uuid4()를 호출합니다. v5는 uuid.uuid5(uuid.NAMESPACE_DNS, "example.com") 형태입니다.
  • Java: UUID.randomUUID()가 v4를 만듭니다.
  • PostgreSQL 13 이상: gen_random_uuid()를 확장 설치 없이 바로 사용할 수 있습니다.
  • MySQL: UUID()는 v1을 반환하므로 v4가 필요하면 애플리케이션 레이어에서 생성하는 편이 낫습니다.

v7은 아직 표준 라이브러리에 포함되지 않은 언어가 많아 별도 패키지가 필요합니다. 다만 구조가 단순해서 밀리초 타임스탬프 48비트와 난수를 조합하는 방식으로 직접 구현하는 사례도 흔합니다.

정리하면 선택 기준은 명확합니다. 데이터베이스 기본키로 새로 설계한다면 v7, 외부에 노출되며 순서를 감춰야 하는 값이라면 v4, 같은 입력에 항상 같은 결과가 필요하다면 v5입니다. v1과 v3은 새 프로젝트에서 굳이 선택할 이유가 없습니다.

자동차 수리가 필요하신가요?

대전 사고차 수리 전문 - 남대전자동차공업사

무료 견적받기