UUID 데이터 타입

UUID 데이터 타입

레코드를 식별하는 16바이트 값인 UUID(Universally Unique Identifier)를 저장하는 데이터 타입이에요. 내부적으로 8-4-4-4-12 표현을 가진 16개의 임의 바이트 시퀀스로 취급돼요.

출처: 문서

본문

UUID(Universally Unique Identifier)는 레코드를 식별하는 데 사용되는 16바이트 값이에요. UUID에 대한 자세한 정보는 Wikipedia를 참고해요. UUIDv4, UUIDv7 같은 다양한 UUID 변형이 존재하지만(RFC 9562 참고), ClickHouse는 삽입된 UUID가 특정 변형을 따르는지 검증하지 않아요. UUID는 내부적으로 SQL 수준에서 8-4-4-4-12 표현을 가진 16개의 임의 바이트 시퀀스로 취급돼요.

예시 UUID 값:

61f0c404-5cb3-11e7-907b-a6006ad3dba0

기본 UUID는 전부 0이에요. 예를 들어 새 레코드를 삽입할 때 UUID 컬럼의 값이 지정되지 않으면 사용돼요.

00000000-0000-0000-0000-000000000000

역사적 이유로 UUID는 자신의 후반부(second half)로 정렬돼요. 이것은 UUIDv4 값에서는 문제없지만, 기본(primary) 인덱스 정의에 사용되는 UUIDv7 컬럼에서는 성능을 저하시킬 수 있어요(정렬 키나 파티션 키 사용은 문제없어요). 더 구체적으로 UUIDv7 값은 전반부에 타임스탬프, 후반부에 카운터로 구성돼요. 따라서 희소 기본 키 인덱스(즉 각 인덱스 그레뉼의 첫 값)에서의 UUIDv7 정렬은 카운터 필드로 이루어져요. UUID가 전반부(타임스탬프)로 정렬된다고 가정하면 쿼리 시작 시 기본 키 인덱스 분석 단계가 한 파트를 제외한 모든 파트의 마크를 제거(prune)할 것으로 기대돼요. 하지만 후반부(카운터)로 정렬하면 모든 파트에 대해 적어도 하나의 마크가 반환될 것으로 기대되어 불필요한 디스크 접근을 유발해요.

예시:

쿼리:

CREATE TABLE tab (uuid UUID) ENGINE = MergeTree PRIMARY KEY (uuid);

INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
SELECT * FROM tab;

응답:

┌─uuid─────────────────────────────────┐
│ 019d2555-7874-7e9d-a284-9b45a0b2f165 │
│ 019d2555-7874-7e9d-a284-9b46c3353be7 │
│ 019d2555-7878-77fc-a36f-4081aa58ec2b │
│ 019d2555-7878-77fc-a36f-40826555fb9b │
│ 019d2555-7870-7432-ba62-5250ac595328 │
│ 019d2555-7870-7432-ba62-5251da22bd19 │
│ 019d2555-786c-73e9-a031-4a7936df7d56 │
│ 019d2555-786c-73e9-a031-4a7a35a9544f │
│ 019d2555-7868-7333-89d1-2bd1639899c3 │
│ 019d2555-7868-7333-89d1-2bd297eb7d42 │
└──────────────────────────────────────┘

해결 방법으로 UUID를 후반부에서 추출한 타임스탬프로 변환할 수 있어요.

쿼리:

CREATE TABLE tab (uuid UUID) ENGINE = MergeTree PRIMARY KEY (UUIDv7ToDateTime(uuid));
-- Or alternatively:                      [...] PRIMARY KEY (toStartOfHour(UUIDv7ToDateTime(uuid)));

INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
INSERT INTO tab SELECT generateUUIDv7() FROM numbers(2);
SELECT * FROM tab;

결과(같은 데이터가 삽입된다고 가정):

응답:

┌─uuid─────────────────────────────────┐
│ 019d2555-7868-7333-89d1-2bd1639899c3 │
│ 019d2555-7868-7333-89d1-2bd297eb7d42 │
│ 019d2555-786c-73e9-a031-4a7936df7d56 │
│ 019d2555-786c-73e9-a031-4a7a35a9544f │
│ 019d2555-7870-7432-ba62-5250ac595328 │
│ 019d2555-7870-7432-ba62-5251da22bd19 │
│ 019d2555-7874-7e9d-a284-9b45a0b2f165 │
│ 019d2555-7874-7e9d-a284-9b46c3353be7 │
│ 019d2555-7878-77fc-a36f-4081aa58ec2b │
│ 019d2555-7878-77fc-a36f-40826555fb9b │
└──────────────────────────────────────┘

ORDER BY (UUIDv7ToDateTime(uuid), uuid)

UUID 생성 (Generating UUIDs)

ClickHouse는 임의의 UUID 버전 4 값을 생성하는 generateUUIDv4 함수를 제공해요.

사용 예시 (Usage Example)

예시 1 (Example 1)

이 예시는 UUID 컬럼이 있는 테이블 생성과 값 삽입을 보여줘요.

쿼리:

CREATE TABLE t_uuid (x UUID, y String) ENGINE=TinyLog

INSERT INTO t_uuid SELECT generateUUIDv4(), 'Example 1'

SELECT * FROM t_uuid

응답:

┌────────────────────────────────────x─┬─y─────────┐
│ 417ddc5d-e556-4d27-95dd-a34d84e46a50 │ Example 1 │
└──────────────────────────────────────┴───────────┘

예시 2 (Example 2)

이 예시에서는 레코드를 삽입할 때 UUID 컬럼 값을 지정하지 않아요. 즉 기본 UUID 값이 삽입돼요.

INSERT INTO t_uuid (y) VALUES ('Example 2')

SELECT * FROM t_uuid
┌────────────────────────────────────x─┬─y─────────┐
│ 417ddc5d-e556-4d27-95dd-a34d84e46a50 │ Example 1 │
│ 00000000-0000-0000-0000-000000000000 │ Example 2 │
└──────────────────────────────────────┴───────────┘

제한 (Restrictions)

UUID 데이터 타입은 String 데이터 타입도 지원하는 함수만 지원해요(예: min, max, count). UUID 데이터 타입은 산술 연산(예: abs)이나 sum, avg 같은 집계 함수를 지원하지 않아요.

더 알아보기 (Learn more)