Enum 데이터 타입

Enum 데이터 타입

이름이 붙은 값들로 구성된 열거 타입이에요. ClickHouse는 숫자만 저장하지만, 값에 대한 연산은 이름을 통해 지원해요. 8비트 Enum은 최대 256개 값, 16비트 Enum은 최대 65536개 값을 담을 수 있어요.

출처: 문서

본문

이름이 붙은 값들로 구성된 열거 타입이에요. 이름 있는 값은 'string' = integer 쌍이나 'string' 이름으로 선언할 수 있어요. ClickHouse는 숫자만 저장하지만, 값에 대한 연산은 이름을 통해 지원해요.

ClickHouse가 지원하는 것은 다음과 같아요.

  • 8비트 Enum — [-128, 127] 범위에 열거된 최대 256개 값을 담을 수 있어요.
  • 16비트 Enum — [-32768, 32767] 범위에 열거된 최대 65536개 값을 담을 수 있어요.

데이터를 넣을 때 ClickHouse가 Enum의 타입을 자동으로 선택해요. 저장 크기를 확실히 하려면 Enum8 또는 Enum16 타입을 쓸 수도 있어요.

사용 예시 (Usage Examples)

여기서 Enum8('hello' = 1, 'world' = 2) 타입 컬럼이 있는 테이블을 만들어 볼게요.

CREATE TABLE t_enum
(
    x Enum('hello' = 1, 'world' = 2)
)
ENGINE = TinyLog

마찬가지로 숫자를 생략할 수도 있어요. ClickHouse가 숫자를 자동으로 연속 배정해요. 기본적으로 숫자는 1부터 시작해요.

CREATE TABLE t_enum
(
    x Enum('hello', 'world')
)
ENGINE = TinyLog

첫 번째 이름에 사용할 합법적인 시작 숫자를 지정할 수도 있어요.

CREATE TABLE t_enum
(
    x Enum('hello' = 1, 'world')
)
ENGINE = TinyLog
CREATE TABLE t_enum
(
    x Enum8('hello' = -129, 'world')
)
ENGINE = TinyLog
Exception on server:
Code: 69. DB::Exception: Value -129 for element 'hello' exceeds range of Enum8.

x 컬럼은 타입 정의에 나열된 값인 'hello' 또는 'world'만 저장할 수 있어요. 다른 값을 저장하려 하면 ClickHouse가 예외를 일으켜요. 이 Enum의 8비트 크기는 자동으로 선택돼요.

INSERT INTO t_enum VALUES ('hello'), ('world'), ('hello')
Ok.
INSERT INTO t_enum VALUES('a')
Exception on client:
Code: 49. DB::Exception: Unknown element 'a' for type Enum('hello' = 1, 'world' = 2)

테이블에서 데이터를 조회하면 ClickHouse가 Enum의 문자열 값을 출력해요.

SELECT * FROM t_enum
┌─x─────┐
│ hello │
│ world │
│ hello │
└───────┘

행의 숫자 등가물을 보려면 Enum 값을 정수 타입으로 캐스팅해야 해요.

SELECT CAST(x, 'Int8') FROM t_enum
┌─CAST(x, 'Int8')─┐
│               1 │
│               2 │
│               1 │
└─────────────────┘

쿼리에서 Enum 값을 만들려면 역시 CAST를 사용해야 해요.

SELECT toTypeName(CAST('a', 'Enum(\'a\' = 1, \'b\' = 2)'))
┌─toTypeName(CAST('a', 'Enum(\'a\' = 1, \'b\' = 2)'))─┐
│ Enum8('a' = 1, 'b' = 2)                             │
└─────────────────────────────────────────────────────┘

일반 규칙과 사용 (General Rules and Usage)

각 값에는 Enum8이면 -128 ... 127 범위, Enum16이면 -32768 ... 32767 범위의 숫자가 배정돼요. 모든 문자열과 숫자는 서로 달라야 해요. 빈 문자열은 허용돼요. (테이블 정의에서) 이 타입을 지정하면 숫자는 임의의 순서일 수 있어요. 단, 순서는 중요하지 않아요.

Enum의 문자열 값과 숫자 값 모두 NULL일 수 없어요. Enum은 Nullable 타입에 담을 수 있어요. 그래서 다음 쿼리로 테이블을 만들면

CREATE TABLE t_enum_nullable
(
    x Nullable(Enum8('hello' = 1, 'world' = 2))
)
ENGINE = TinyLog

'hello', 'world'뿐 아니라 NULL도 저장할 수 있어요.

INSERT INTO t_enum_nullable VALUES('hello'),('world'),(NULL)

RAM에서 Enum 컬럼은 해당 숫자 값의 Int8 또는 Int16과 같은 방식으로 저장돼요. 텍스트 형식으로 읽을 때 ClickHouse는 값을 문자열로 파싱해 Enum 값 집합에서 해당 문자열을 찾아요. 찾지 못하면 예외가 던져져요. 텍스트 형식으로 쓸 때는 값을 해당 문자열로 써요. 컬럼 데이터에 쓰레기(유효 집합에 없는 숫자)가 있으면 예외가 던져져요. 이진 형식으로 읽고 쓸 때는 Int8, Int16 데이터 타입과 동일하게 동작해요.

암시적 기본값은 가장 낮은 숫자를 가진 값이에요. ORDER BY, GROUP BY, IN, DISTINCT 등에서 Enum은 해당 숫자와 같은 방식으로 동작해요. 예를 들어 ORDER BY는 숫자로 정렬해요. 동등·비교 연산자도 하부 숫자 값과 동일하게 Enum에서 동작해요.

Enum 값은 숫자와 비교할 수 없어요. Enum은 상수 문자열과 비교할 수 있어요. 비교 대상 문자열이 Enum의 유효한 값이 아니면 예외가 던져져요. IN 연산자는 왼쪽에 Enum, 오른쪽에 문자열 집합을 두고 지원돼요. 그 문자열들은 해당 Enum의 값들이에요.

대부분의 숫자·문자열 연산은 Enum 값에 대해 정의되지 않아요. 예를 들어 Enum에 숫자를 더하거나 Enum에 문자열을 연결하는 것은 불가능해요. 하지만 Enum에는 문자열 값을 반환하는 자연스러운 toString 함수가 있어요. Enum 값은 toT 함수(T는 숫자 타입)로 숫자 타입으로도 변환할 수 있어요. T가 Enum의 하부 숫자 타입에 해당하면 이 변환은 비용이 0이에요.

ALTER로 값의 집합만 바꾸는 경우 Enum 타입은 비용 없이 변경할 수 있어요. ALTER로 Enum의 멤버를 추가하고 제거하는 것이 모두 가능해요(제거는 제거된 값이 테이블에서 한 번도 사용된 적 없을 때만 안전해요). 안전 장치로, 기존에 정의된 Enum 멤버의 숫자 값을 바꾸면 예외가 던져져요.

ALTER를 사용하면 Int8을 Int16으로 바꾸는 것처럼 Enum8을 Enum16으로 또는 그 반대로 바꿀 수 있어요.

ENUM 값 추가 (ADD ENUM VALUES)

ALTER MODIFY COLUMN ADD ENUM VALUES를 사용해 enum에 새 값을 추가하는 문법적 설탕(syntactic sugar)이 있어요.

CREATE TABLE enum
(
    x Enum('One' = 1, 'Two', 'Three')
) ENGINE = Memory;
ALTER TABLE enum MODIFY COLUMN x ADD ENUM VALUES ('Zero' = 0, 'Four' = 4);
SHOW CREATE TABLE enum;
┌─statement────────────────────────────────────────────────────────────────┐
│CREATE TABLE default.enum                                                 │
│(                                                                         │
│    `x` Enum8('Zero' = 0, 'One' = 1, 'Two' = 2, 'Three' = 3, 'Four' = 4)  │
│)                                                                         │
│ENGINE = Memory                                                           │
└──────────────────────────────────────────────────────────────────────────┘

더 알아보기 (Learn more)