UUID v7 생성기

Generate time-ordered UUID v7 for database primary keys

포맷

개수:

UUID v7이란 무엇인가요?

UUID v7은 RFC 9562(2024년 5월)에서 표준화된 차세대 UUID 형식입니다. 최상위 비트에 48비트 Unix 밀리초 타임스탬프를 인코딩하고, 버전 및 변형 마커를 뒤따르며, 나머지 비트를 암호학적으로 안전한 무작위 데이터로 채웁니다.

타임스탬프가 상위 비트를 차지하기 때문에 UUID v7 값은 시간순으로 정렬됩니다——사전순으로도 수치적으로도. 이로 인해 무작위 UUID(v4)가 B-tree 인덱스 단편화를 유발하는 데이터베이스 기본 키로 탁월한 선택입니다.

무작위 UUID가 데이터베이스 인덱스를 단편화시키는 이유

B-tree 인덱스——PostgreSQL, MySQL, SQLite 및 대부분의 다른 데이터베이스에서 사용——는 행을 키 값으로 정렬된 상태로 유지합니다. 새 행을 삽입할 때 데이터베이스는 인덱스 트리에서 올바른 정렬 위치에 배치해야 합니다.

UUID v4(완전히 무작위)의 경우 각 새 삽입은 인덱스 트리의 본질적으로 무작위 위치에 떨어집니다. 이로 인해 데이터베이스는 내부 인덱스 페이지를 지속적으로 읽고 다시 쓰며, 가득 찬 페이지를 분할하고 다른 페이지를 절반 비어있게 만듭니다. 결과는 테이블이 커짐에 따라 쓰기와 읽기 모두 느리게 만드는 단편화되고 비대해진 인덱스입니다.

UUID v7 비트 레이아웃

UUID v7은 128비트 너비로 6개 필드로 나뉩니다:

비트필드목적
48unix_ts_ms밀리초 단위 48비트 Unix 타임스탬프——전체 상위 절반을 차지
4ver버전 번호——항상 0111(10진수 7)
12rand_a12비트 암호학적으로 안전한 무작위 데이터
2var변형 마커——항상 10(RFC 4122 변형)
62rand_b62비트 암호학적으로 안전한 무작위 데이터

타임스탬프 정밀도는 1밀리초입니다. 같은 밀리초 내에서 UUID v7 값은 무작위 접미사로 정렬됩니다——밀리초 이하의 단조 증가는 보장되지 않지만 k-sortable입니다: 시간적으로 가깝게 생성된 ID는 인덱스에서도 가깝게 정렬됩니다.

UUID v7 대 UUID v1

UUID v1과 UUID v7 모두 타임스탬프를 내장하지만 설계가 크게 다릅니다:

기능UUID v7UUID v1
에포크 / 시간 기준Unix 에포크(1970년 1월 1일)그레고리안 에포크(1582년 10월 15일)
시간 정밀도1밀리초100나노초
정렬 가능예——설계상 k-sortable아니오——시간 필드가 UUID 레이아웃에서 뒤섞임
프라이버시호스트 정보 누출 없음생성 호스트의 MAC 주소 내장
DB 인덱스 성능탁월——순차 삽입, 단편화 최소불량——타임스탬프에도 불구하고 비순차
표준RFC 9562(2024)RFC 4122(2005)
네이티브 브라우저 지원아직 없음(crypto.randomUUID v7 없음)네이티브로 사용 불가

시간 순서 UUID가 필요한 새 프로젝트에서는 UUID v1보다 UUID v7을 선호하세요. UUID v1은 레거시이며 호스트 정보를 누출합니다.

UUID v7 대 ULID

ULID(Universally Unique Lexicographically Sortable Identifier)는 UUID v7과 유사한 문제를 해결합니다. 비교:

UUID v7
  • RFC 9562 UUID 표준 준수——모든 UUID 도구와 호환
  • 하이픈 16진 형식——보편적으로 인식됨
  • 네이티브 데이터베이스 UUID 열 지원
  • 총 128비트
ULID
  • Crockford Base32 인코딩——26자, 약간 더 압축
  • 대소문자 구분 없고 모호한 문자(I, L, O, U) 회피
  • 한눈에 더 읽기 쉬움
  • 라이브러리 필요——네이티브 플랫폼 지원 없음

이미 UUID 생태계(PostgreSQL uuid 열, UUID를 반환하는 REST API)에 있다면 UUID v7을 사용하세요. 처음부터 시작하고 더 인간 친화적인 인코딩을 선호한다면 ULID가 합리적인 대안입니다.

데이터베이스에서 UUID v7 사용

UUID v7은 아직 대부분의 데이터베이스에서 네이티브로 생성되지 않지만 표준 UUID 열에 저장하고 애플리케이션 코드 또는 확장을 통해 생성할 수 있습니다:

PostgreSQL
PostgreSQL: uuid 열에 저장합니다. DB 생성 ID가 필요하면 pg-uuidv7 확장이 uuid_generate_v7() 서버 측 함수를 추가합니다.
MySQL / MariaDB
MySQL / MariaDB: BINARY(16) 또는 CHAR(36) 열에 저장합니다. 애플리케이션 코드에서 생성합니다. MySQL 8.0+는 v1에 대해 UUID_TO_BIN(UUID(), 1)을 통한 순서 있는 UUID를 지원하지만 v7은 앱 수준 생성이 필요합니다.
SQLite
SQLite: TEXT(36자) 또는 BLOB(16바이트)로 저장합니다. 애플리케이션 코드에서 생성합니다. UUID v7은 고정 너비 타임스탬프 접두사를 사용하므로 TEXT의 사전순 정렬이 올바르게 작동합니다.

코드 예제

UUID v7은 아직 crypto.randomUUID()로 사용할 수 없습니다. 네이티브 지원이 올 때까지 uuidv7(npm)와 같은 라이브러리를 사용하세요:

JavaScript (browser / Node.js 20+)
function generateUuidV7() {
  const buf = new Uint8Array(16)
  crypto.getRandomValues(buf)

  const ms = BigInt(Date.now())

  // Embed 48-bit Unix ms timestamp
  buf[0] = Number((ms >> 40n) & 0xFFn)
  buf[1] = Number((ms >> 32n) & 0xFFn)
  buf[2] = Number((ms >> 24n) & 0xFFn)
  buf[3] = Number((ms >> 16n) & 0xFFn)
  buf[4] = Number((ms >> 8n)  & 0xFFn)
  buf[5] = Number(ms & 0xFFn)

  // Set version 7 (0111xxxx)
  buf[6] = (buf[6] & 0x0F) | 0x70

  // Set variant (10xxxxxx)
  buf[8] = (buf[8] & 0x3F) | 0x80

  const hex = [...buf].map(b => b.toString(16).padStart(2, '0')).join('')
  return `${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`
}

// Node.js 20+ built-in
// import { randomUUID } from 'node:crypto'  // v4 only — no v7 yet in stdlib
Python (uuid7 library)
# pip install uuid7
import uuid_extensions

uid = uuid_extensions.uuid7()
print(uid)                       # e.g. 018e2b3d-1a2b-7000-8000-abc123456789
print(uid.time)                  # Unix ms timestamp embedded in the UUID

# Or as a plain string
from uuid_extensions import uuid7str
print(uuid7str())
PostgreSQL — generate UUID v7
-- PostgreSQL 13+ extension-free implementation
CREATE OR REPLACE FUNCTION uuid_generate_v7()
RETURNS uuid
LANGUAGE sql
AS $$
  SELECT encode(
    set_bit(
      set_bit(
        overlay(
          uuid_send(gen_random_uuid())
          PLACING substring(int8send(floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint) FROM 3)
          FROM 1 FOR 6
        ),
        52, 1
      ),
      53, 1
    ),
    'hex'
  )::uuid;
$$;

-- Usage as a default primary key
CREATE TABLE events (
  id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
  payload jsonb,
  created_at timestamptz DEFAULT now()
);
TypeScript — extract timestamp from UUID v7
function extractTimestamp(uuid: string): Date {
  const hex = uuid.replace(/-/g, '')
  const ms = parseInt(hex.slice(0, 12), 16)  // first 48 bits = ms timestamp
  return new Date(ms)
}

const uid = '018e2b3d-1a2b-7000-8000-abc123456789'
console.log(extractTimestamp(uid).toISOString())
// → "2024-03-15T10:22:05.259Z"

자주 묻는 질문

UUID v7은 UUID v4와 하위 호환성이 있나요?
예. UUID v7은 다른 모든 UUID 버전과 동일한 128비트, 32자 16진, 하이픈 와이어 형식을 사용합니다. UUID를 저장하거나 전송하는 모든 시스템은 변경 없이 UUID v7을 허용합니다.
UUID v7은 생성 타임스탬프를 노출하나요?
예——처음 48비트가 Unix 밀리초 타임스탬프이므로 UUID를 가진 사람은 누구나 생성 시간을 대략(가장 가까운 밀리초까지) 알 수 있습니다. 생성 시간 노출이 사용 사례에서 우려 사항이라면 대신 UUID v4를 사용하세요.
UUID v7을 별도의 created_at 열 없이 데이터베이스 기본 키로 사용할 수 있나요?
예. UUID v7은 밀리초 정밀도 타임스탬프를 내장하므로 해당 값을 디코딩하여 대략적인 생성 시간을 알 수 있습니다. 그러나 명확성과 인덱싱 가능성을 위해 많은 팀이 여전히 명시적인 created_at 열을 유지하고 ID 열에만 UUID v7을 사용합니다.
UUID v7의 엔트로피는 얼마나 되나요?
UUID v7은 74비트의 무작위 데이터(rand_a의 12비트 + rand_b의 62비트)를 가집니다. UUID v4의 122비트보다 약간 적지만 실제 사용을 위한 천문학적으로 큰 충돌 없는 공간을 제공합니다.
UUID v7은 브라우저나 Node.js에서 네이티브로 지원되나요?
2025년 초 현재 아직 아닙니다. RFC 9562 표준은 2024년 5월에 발행되었으며 플랫폼 지원이 아직 따라오고 있습니다. 지금은 uuidv7 npm 패키지를 사용하세요.