ON CLUSTER 절로 구현되며, 이에 대해서는 별도로 설명합니다.
구문 형식
명시적 스키마 사용
db가 설정되어 있으면 db 데이터베이스에, 설정되어 있지 않으면 현재 데이터베이스에, 대괄호 안에 지정된 구조와 engine 엔진으로 table_name이라는 이름의 테이블을 생성합니다.
테이블의 구조는 컬럼 설명, 보조 인덱스, 프로젝션, 제약 조건의 목록입니다. 엔진이 기본 키(primary key)를 지원하는 경우, 이는 테이블 엔진의 매개변수로 지정됩니다.
가장 단순한 경우 컬럼 설명은 name type 형식입니다. 예시: RegionID UInt32.
기본값에 대한 표현식도 정의할 수 있습니다(아래 참조).
필요한 경우 하나 이상의 키 표현식과 함께 기본 키를 지정할 수 있습니다.
컬럼과 테이블에 주석을 추가할 수 있습니다.
기존 테이블 스키마 사용
기존 테이블의 스키마와 데이터 복제
db.table의 모든 파티션이 이 테이블에 ATTACH됩니다. 즉, 생성과 동시에 db.table의 데이터가 db2.table_clone으로 복제됩니다. 이 쿼리는 다음과 동일합니다.
db.table)과 동일한 엔진이 사용됩니다.
테이블 함수에서
SELECT 쿼리에서
SELECT 쿼리 결과와 같은 구조의 테이블을 engine 엔진으로 생성하고, SELECT의 데이터로 채웁니다. 또한 컬럼 정의를 명시적으로 지정할 수도 있습니다.
테이블이 이미 존재하고 IF NOT EXISTS가 지정된 경우, 쿼리는 아무 작업도 수행하지 않습니다.
쿼리에서는 ENGINE 절 뒤에 다른 절이 올 수 있습니다. 테이블을 생성하는 방법에 대한 자세한 내용은 테이블 엔진 설명서를 참조하십시오.
예시
Query
Response
NULL 또는 NOT NULL 수정자
NULL 및 NOT NULL 수정자는 해당 타입을 널 허용(Nullable)으로 만들거나 그렇지 않게 만듭니다.
타입이 Nullable이 아닌 상태에서 NULL이 지정되면 Nullable로 처리되며, NOT NULL이 지정되면 그렇게 처리되지 않습니다. 예를 들어 INT NULL은 Nullable(INT)와 같습니다. 타입이 이미 Nullable인데 NULL 또는 NOT NULL 수정자를 지정하면 예외가 발생합니다.
관련 항목: data_type_default_nullable 설정.
기본값
DEFAULT expr, MATERIALIZED expr 또는 ALIAS expr 형태의 기본값 표현식을 지정할 수 있습니다. 예시: URLDomain String DEFAULT domain(URL).
표현식 expr은 선택 사항입니다. 이를 생략하면 컬럼 타입을 명시적으로 지정해야 하며, 기본값은 숫자 컬럼은 0, 문자열 컬럼은 ''(빈 문자열), 배열 컬럼은 [](빈 배열), 날짜 컬럼은 1970-01-01, 널 허용 컬럼은 NULL이 됩니다.
기본값 컬럼의 컬럼 타입은 생략할 수 있으며, 이 경우 expr의 타입에서 추론됩니다. 예를 들어 EventDate DEFAULT toDate(EventTime) 컬럼의 타입은 Date가 됩니다.
데이터 타입과 기본값 표현식을 모두 지정하면, 표현식을 지정된 타입으로 변환하는 암시적 형 변환 함수가 삽입됩니다. 예시: Hits UInt32 DEFAULT 0은 내부적으로 Hits UInt32 DEFAULT toUInt32(0)으로 표현됩니다.
기본값 표현식 expr은 임의의 테이블 컬럼과 상수를 참조할 수 있습니다. ClickHouse는 테이블 구조 변경으로 인해 표현식 계산에 루프가 생기지 않는지 확인합니다. INSERT에서는 표현식을 해석할 수 있는지, 즉 해당 표현식을 계산하는 데 필요한 모든 컬럼이 전달되었는지 확인합니다.
DEFAULT
DEFAULT expr
일반적인 기본값입니다. 이러한 컬럼의 값이 INSERT 쿼리에서 지정되지 않으면 expr에서 계산됩니다.
예시:
MATERIALIZED
MATERIALIZED expr
구체화된 표현식입니다. 이러한 컬럼의 값은 행이 삽입될 때 지정된 구체화된 표현식에 따라 자동으로 계산됩니다. INSERT 시에는 값을 명시적으로 지정할 수 없습니다.
또한 이 유형의 기본값 컬럼은 SELECT * 결과에 포함되지 않습니다. 이는 SELECT *의 결과를 항상 INSERT를 사용해 다시 테이블에 삽입할 수 있다는 조건을 유지하기 위한 것입니다. 이 동작은 설정 asterisk_include_materialized_columns으로 비활성화할 수 있습니다.
예시:
EPHEMERAL
EPHEMERAL [expr]
임시 컬럼입니다. 이 유형의 컬럼은 테이블에 저장되지 않으며 SELECT할 수도 없습니다. 임시 컬럼의 유일한 용도는 이를 사용해 다른 컬럼의 기본값 표현식을 구성하는 것입니다.
컬럼을 명시적으로 지정하지 않고 수행하는 삽입은 이 유형의 컬럼을 건너뜁니다. 이는 SELECT *의 결과를 항상 INSERT를 사용해 다시 테이블에 삽입할 수 있다는 불변성을 유지하기 위한 것입니다.
예시:
ALIAS
ALIAS expr
계산된 컬럼의 동의어입니다. 이 유형의 컬럼은 테이블에 저장되지 않으며, 여기에 값을 INSERT할 수 없습니다.
SELECT 쿼리에서 이 유형의 컬럼을 명시적으로 참조하면 값은 expr로부터 쿼리 시점에 계산됩니다. 기본적으로 SELECT *에는 ALIAS 컬럼이 포함되지 않습니다. 이 동작은 설정 asterisk_include_alias_columns로 비활성화할 수 있습니다.
ALTER 쿼리를 사용해 새 컬럼을 추가하면 해당 컬럼의 기존 데이터는 기록되지 않습니다. 대신 기본적으로는 새 컬럼 값이 없는 기존 데이터를 읽을 때 표현식이 즉시 계산됩니다. 하지만 표현식을 실행하는 데 쿼리에 지정되지 않은 다른 컬럼이 필요하면 해당 컬럼도 추가로 읽히며, 필요한 데이터 블록에 대해서만 읽습니다.
테이블에 새 컬럼을 추가한 뒤 나중에 해당 컬럼의 기본 표현식을 변경하면, 기존 데이터에 사용되는 값도 변경됩니다(디스크에 값이 저장되지 않은 데이터의 경우). 백그라운드 머지가 실행될 때 머지되는 파트 중 하나에 없는 컬럼의 데이터는 병합된 파트에 기록된다는 점에 유의하십시오.
중첩 데이터 구조의 요소에는 기본값을 설정할 수 없습니다.
테이블을 생성할 때 기본 키를 정의할 수 있습니다. 기본 키는 다음 두 가지 방식으로 지정할 수 있습니다.
- 컬럼 목록 안에서
- 컬럼 목록 밖
제약 조건
CONSTRAINT
boolean_expr_1에는 임의의 불리언 표현식이 올 수 있습니다. 테이블에 제약 조건이 정의되어 있으면 INSERT 쿼리에서 각 행마다 모든 제약 조건을 검사합니다. 제약 조건 중 하나라도 충족되지 않으면 서버는 제약 조건 이름과 검사 표현식을 포함한 예외를 발생시킵니다.
제약 조건을 너무 많이 추가하면 대규모 INSERT 쿼리의 성능에 부정적인 영향을 줄 수 있습니다.
ASSUME
ASSUME 절은 테이블에서 참이라고 가정하는 CONSTRAINT를 정의하는 데 사용됩니다. 이렇게 정의한 제약 조건은 이후 최적화기가 SQL 쿼리 성능을 향상하는 데 활용할 수 있습니다.
다음은 ASSUME CONSTRAINT를 사용해 users_a 테이블을 생성하는 예시입니다:
ASSUME CONSTRAINT를 사용해 length(name) 함수의 결과가 항상 name_len 컬럼 값과 같다고 가정합니다. 즉, 쿼리에서 length(name)가 호출될 때마다 ClickHouse는 이를 name_len으로 대체할 수 있으며, length() 함수를 호출할 필요가 없으므로 더 빠를 수 있습니다.
그다음 SELECT name FROM users_a WHERE length(name) < 5; 쿼리를 실행하면 ClickHouse는 ASSUME CONSTRAINT를 바탕으로 이를 SELECT name FROM users_a WHERE name_len < 5로 최적화할 수 있습니다. 이렇게 하면 각 행마다 name의 길이를 계산하지 않아도 되므로 쿼리가 더 빠르게 실행될 수 있습니다.
ASSUME CONSTRAINT는 제약 조건을 강제하지 않으며, 단지 해당 제약 조건이 참이라고 옵티마이저에 알려 줄 뿐입니다. 제약 조건이 실제로 참이 아니면 쿼리 결과가 올바르지 않을 수 있습니다. 따라서 제약 조건이 참이라고 확신할 때만 ASSUME CONSTRAINT를 사용해야 합니다.
TTL 표현식
컬럼 압축 코덱
lz4 압축을 사용하고, ClickHouse Cloud에서는 zstd를 사용합니다.
MergeTree 엔진 계열의 경우 서버 구성의 압축 섹션에서 기본 압축 방식을 변경할 수 있습니다.
또한 CREATE TABLE 쿼리에서 각 컬럼별 압축 방식을 정의할 수도 있습니다.
Default 코덱을 지정하면 기본 압축을 참조할 수 있습니다. 이 기본 압축은 런타임의 여러 설정(및 데이터 속성)에 따라 달라질 수 있습니다.
예시: value UInt64 CODEC(Default) — 코덱을 지정하지 않은 것과 같습니다.
또한 컬럼에서 현재 CODEC을 제거하고 config.xml에 설정된 기본 압축을 사용할 수도 있습니다:
CODEC(Delta, Default)가 있습니다.
다음 테이블 엔진은 압축을 지원합니다.
- MergeTree 계열. 컬럼 압축 코덱을 지원하며, compression 설정을 통해 기본 압축 방식을 선택할 수 있습니다.
- Log 계열. 기본적으로
lz4압축 방식을 사용하며 컬럼 압축 코덱을 지원합니다. - Set. 기본 압축만 지원합니다.
- Join. 기본 압축만 지원합니다.
범용 코덱
NONE
NONE — 압축을 사용하지 않습니다.
LZ4
LZ4 — 기본적으로 사용되는 무손실 데이터 압축 알고리즘입니다. 빠른 LZ4 압축을 적용합니다.
LZ4HC
LZ4HC[(level)] — 레벨을 구성할 수 있는 LZ4 HC(고압축) 알고리즘입니다. 기본 레벨: 9. level <= 0으로 설정하면 기본 레벨이 적용됩니다. 가능한 레벨: [1, 12]. 권장 레벨 범위: [4, 9].
ZSTD
ZSTD[(level)] — level을 구성할 수 있는 ZSTD 압축 알고리즘입니다. 가능한 수준은 [1, 22]입니다. 기본 수준은 1입니다.
높은 압축 수준은 한 번 압축한 뒤 반복적으로 압축을 해제하는 것과 같은 비대칭 시나리오에서 유용합니다. 수준이 높을수록 압축률은 좋아지지만 CPU 사용량도 증가합니다.
사용 중단: ZSTD_QAT
더 이상 사용되지 않음: DEFLATE_QPL
특수 코덱
Delta
Delta(delta_bytes) — 첫 번째 값은 그대로 두고, 원본 값을 인접한 두 값의 차이로 대체하는 압축 방식입니다. delta_bytes는 원본 값의 최대 크기이며, 기본값은 sizeof(type)입니다. delta_bytes를 인수로 지정하는 방식은 더 이상 권장되지 않으며, 향후 릴리스에서 지원이 제거될 예정입니다. Delta는 데이터 전처리 코덱이므로 단독으로 사용할 수 없습니다.
DoubleDelta
DoubleDelta(bytes_size) — 델타의 델타를 계산하여 압축된 이진 형식으로 기록합니다. bytes_size는 Delta 코덱의 delta_bytes와 유사한 의미를 가집니다. bytes_size를 인수로 지정하는 방식은 더 이상 권장되지 않으며, 향후 릴리스에서 지원이 제거될 예정입니다. 시계열 데이터처럼 일정한 보폭으로 증가하는 단조 시퀀스에서 최적의 압축률을 얻을 수 있습니다. 모든 숫자 타입에 사용할 수 있습니다. Gorilla TSDB에서 사용하는 알고리즘을 구현하며, 이를 확장해 64비트 타입도 지원합니다. 32비트 델타에는 추가로 1비트를 사용합니다. 즉, 4비트 프리픽스 대신 5비트 프리픽스를 사용합니다. 자세한 내용은 Gorilla: A Fast, Scalable, In-Memory Time Series Database의 Compressing Time Stamps를 참조하십시오. DoubleDelta는 데이터 준비용 코덱이므로 단독으로는 사용할 수 없습니다.
GCD
GCD() - - 컬럼의 값들에 대한 최대공약수(GCD)를 계산한 다음, 각 값을 GCD로 나눕니다. 정수, decimal 및 날짜/시간 컬럼에 사용할 수 있습니다. 이 코덱은 값이 GCD의 배수 단위로 변하는(증가하거나 감소하는) 컬럼에 특히 적합합니다. 예를 들어 24, 28, 16, 24, 8, 24(GCD = 4)와 같은 경우입니다. GCD는 데이터 준비 코덱이므로 단독으로는 사용할 수 없습니다.
Gorilla
Gorilla(bytes_size) — 현재 부동소수점 값과 이전 부동소수점 값의 XOR를 계산해 이를 압축된 바이너리 형식으로 기록합니다. 연속된 값 사이의 차이가 작을수록, 즉 시계열 값이 더 천천히 변할수록 압축률이 더 높아집니다. Gorilla TSDB에서 사용하는 알고리즘을 구현하며, 이를 확장해 64비트 타입도 지원합니다. 가능한 bytes_size 값은 1, 2, 4, 8이며, 기본값은 sizeof(type)이 1, 2, 4, 8 중 하나이면 sizeof(type)입니다. 그 외의 경우에는 1입니다. 추가 정보는 Gorilla: A Fast, Scalable, In-Memory Time Series Database의 4.1절을 참조하십시오.
ALP
ALP() — 10진 스케일링을 기반으로 하는 부동소수점 데이터용 적응형 무손실 압축입니다. ALP는 각 값을 10의 거듭제곱을 사용해 정확한 스케일된 정수로 표현한 뒤, 생성된 정수를 Frame-of-Reference와 비트 패킹으로 압축하려고 시도합니다. 정확하게 표현할 수 없는 값은 예외 값으로 원본 그대로 저장됩니다. 10진수에서 유래한 숫자(예: 측정값, 통화)에 가장 효과적입니다. Float32 및 Float64를 지원합니다. 자세한 내용은 ALP: Adaptive lossless floating-point compression을 참조하십시오.
이 코덱은 실험적 기능이며, 사용하려면
SET allow_experimental_codecs = 1을 설정해야 합니다.FPC
FPC(level, float_size) - 두 가지 예측기 중 더 나은 쪽을 사용해 시퀀스의 다음 부동소수점 값을 반복적으로 예측한 다음, 실제 값과 예측값에 XOR를 수행하고, 결과를 선행 0으로 압축합니다. Gorilla와 유사하게, 천천히 변하는 일련의 부동소수점 값을 저장할 때 효율적입니다. 64비트 값(double)의 경우 FPC가 Gorilla보다 더 빠르지만, 32비트 값에서는 경우에 따라 다를 수 있습니다. 가능한 level 값은 1-28이며 기본값은 12입니다. 가능한 float_size 값은 4, 8이며, 타입이 Float인 경우 기본값은 sizeof(type)입니다. 그 밖의 모든 경우에는 4입니다. 알고리즘에 대한 자세한 설명은 High Throughput Compression of Double-Precision Floating-Point Data를 참조하십시오.
T64
T64 — Enum, Date, DateTime을 포함한 정수 데이터 타입에서 사용되지 않는 상위 비트를 잘라내는 압축 방식입니다. 이 알고리즘의 각 단계에서 코덱은 64개의 값으로 이루어진 블록을 64x64 비트 행렬에 배치하고 이를 전치한 다음, 값에서 사용되지 않는 비트를 잘라내고 나머지를 순차열로 반환합니다. 사용되지 않는 비트는 압축이 적용되는 전체 데이터 파트(data part)에서 최댓값과 최솟값 사이에 차이가 없는 비트를 의미합니다.
DoubleDelta 및 Gorilla 코덱은 Gorilla TSDB의 압축 알고리즘을 구성하는 요소로 사용됩니다. Gorilla 방식은 timestamp와 함께 천천히 변하는 값들의 시퀀스가 있는 경우에 효과적입니다. timestamp는 DoubleDelta 코덱으로 효율적으로 압축되고, 값은 Gorilla 코덱으로 효율적으로 압축됩니다. 예를 들어, 테이블을 효율적으로 저장하려면 다음과 같은 구성으로 생성할 수 있습니다:
암호화 코덱
AES_128_GCM_SIV
CODEC('AES-128-GCM-SIV') — RFC 8452에 정의된 GCM-SIV 모드로 AES-128을 사용해 데이터를 암호화합니다.
AES-256-GCM-SIV
CODEC('AES-256-GCM-SIV') — AES-256을 GCM-SIV 모드로 사용해 데이터를 암호화합니다.
이 코덱은 고정 nonce를 사용하므로 암호화가 결정적입니다. 따라서 ReplicatedMergeTree와 같은 중복 제거 엔진과 호환되지만, 약점도 있습니다. 동일한 데이터 블록을 두 번 암호화하면 결과 암호문이 완전히 동일해지므로, 디스크를 읽을 수 있는 공격자는 이 둘이 동일하다는 사실을 알아낼 수 있습니다(내용 자체는 알 수 없고 동일 여부만 확인할 수 있습니다).
“*MergeTree” 계열을 포함한 대부분의 엔진은 코덱을 적용하지 않은 채 디스크에 인덱스 파일을 생성합니다. 즉, 암호화된 컬럼에 인덱스가 있으면 평문이 디스크에 기록됩니다.
암호화된 컬럼의 특정 값을 명시하는 SELECT 쿼리(예: WHERE 절)를 수행하면 해당 값이 system.query_log에 나타날 수 있습니다. 로깅을 비활성화하는 것이 좋을 수 있습니다.
압축이 필요한 경우 명시적으로 지정해야 합니다. 그렇지 않으면 데이터에는 암호화만 적용됩니다.
임시 테이블
임시 테이블은 복제되지 않는다는 점에 유의하십시오. 따라서 임시 테이블에 삽입된 데이터가 다른 레플리카에서도 사용 가능하다고 보장할 수는 없습니다. 임시 테이블은 단일 세션 동안 작은 외부 데이터셋을 쿼리하거나 조인할 때 주로 유용합니다.
- 임시 테이블은 연결이 끊어진 경우를 포함하여 세션이 종료되면 사라집니다.
- 임시 테이블은 엔진이 지정되지 않으면 Memory 테이블 엔진을 사용하며, Replicated 및
KeeperMap엔진을 제외한 모든 테이블 엔진을 사용할 수 있습니다. - 임시 테이블에는 DB를 지정할 수 없습니다. 데이터베이스 외부에 생성됩니다.
- 모든 cluster 서버에 분산 DDL 쿼리(
ON CLUSTER사용)로 임시 테이블을 생성할 수 없습니다. 이 테이블은 현재 세션에만 존재합니다. - 임시 테이블의 이름이 다른 테이블과 같고, 쿼리에서 DB를 지정하지 않은 채 테이블 이름만 지정하면 임시 테이블이 사용됩니다.
- 분산 쿼리 처리 시에는 쿼리에서 사용된 Memory 엔진 임시 테이블이 원격 서버로 전달됩니다.
(GLOBAL) IN을 사용할 때만 생성됩니다. 자세한 내용은 해당 섹션을 참조하십시오
임시 테이블 대신 ENGINE = Memory 테이블을 사용할 수도 있습니다.
REPLACE TABLE
REPLACE 문을 사용하면 테이블을 원자적으로 업데이트할 수 있습니다.
이 문은
Atomic 및 Replicated 데이터베이스 엔진(database engines)에서 지원되며,
각각 ClickHouse와 ClickHouse Cloud의 기본 데이터베이스 엔진입니다.SELECT 문으로 새 테이블을 만들고 데이터를 채운 다음,
기존 테이블을 삭제하고 새 테이블로 이름을 변경할 수 있습니다.
이 방법은 아래 예시에서 보여줍니다.
REPLACE를 사용할 수도 있습니다(기본 데이터베이스 엔진을 사용하는 경우):
구문
CREATE 문의 모든 구문 형식은 이 문에도 사용할 수 있습니다. 존재하지 않는 테이블에 REPLACE를 실행하면 오류가 발생합니다.예시:
- 로컬
- Cloud
다음 테이블을 예로 들어 보겠습니다.또는
REPLACE 구문을 사용해 모든 데이터를 비울 수 있습니다:REPLACE 구문을 사용해 테이블 구조를 변경할 수 있습니다:COMMENT 절
COMMENT 절은 PARTITION BY, ORDER BY, 스토리지별 SETTINGS와 같은 모든 스토리지 관련 절 뒤에 지정해야 합니다.COMMENT 절 뒤에서는 스토리지 관련 설정이 아니라 max_threads 등과 같은 쿼리별 SETTINGS만 구문 분석됩니다.즉, 올바른 절 순서는 다음과 같습니다.ENGINE- 스토리지 절
COMMENT- 쿼리 설정(있는 경우)
Query
Response