메인 콘텐츠로 건너뛰기
테이블에 데이터를 삽입합니다. 구문
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] [SETTINGS ...] VALUES (v11, v12, v13), (v21, v22, v23), ...
삽입할 컬럼 목록은 (c1, c2, c3)를 사용하여 지정할 수 있습니다. 또한 *와 같은 컬럼 matcher 표현식이나 APPLY, EXCEPT, REPLACE와 같은 수정자도 사용할 수 있습니다. 예시로, 다음 테이블을 살펴보겠습니다:
SHOW CREATE insert_select_testtable;
CREATE TABLE insert_select_testtable
(
    `a` Int8,
    `b` String,
    `c` Int8
)
ENGINE = MergeTree()
ORDER BY a
INSERT INTO insert_select_testtable (*) VALUES (1, 'a', 1) ;
b 컬럼을 제외한 모든 컬럼에 데이터를 삽입하려면 EXCEPT 키워드를 사용할 수 있습니다. 위 구문과 관련해, 지정한 컬럼((c1, c3))의 개수와 삽입하는 값(VALUES (v11, v13))의 개수가 같도록 해야 합니다:
INSERT INTO insert_select_testtable (* EXCEPT(b)) Values (2, 2);
SELECT * FROM insert_select_testtable;
┌─a─┬─b─┬─c─┐
│ 2 │   │ 2 │
└───┴───┴───┘
┌─a─┬─b─┬─c─┐
│ 1 │ a │ 1 │
└───┴───┴───┘
이 예시에서는 두 번째로 삽입된 행에서 ac 컬럼은 전달된 값으로 채워지고, b는 기본적으로 기본값으로 채워지는 것을 확인할 수 있습니다. 또한 DEFAULT 키워드를 사용해 기본값을 삽입할 수도 있습니다:
INSERT INTO insert_select_testtable VALUES (1, DEFAULT, 1) ;
컬럼 목록에 기존 컬럼이 모두 포함되어 있지 않으면, 나머지 컬럼은 다음 값으로 채워집니다:
  • 테이블 정의(table definition)에 지정된 DEFAULT 표현식으로 계산된 값
  • DEFAULT 표현식이 정의되어 있지 않으면 0과 빈 문자열
데이터는 ClickHouse가 지원하는 임의의 포맷으로 INSERT에 전달할 수 있습니다. 포맷은 쿼리에서 명시적으로 지정해야 합니다:
INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set
예를 들어, 다음 쿼리 포맷은 INSERT ... VALUES의 기본형과 동일합니다:
INSERT INTO [db.]table [(c1, c2, c3)] FORMAT Values (v11, v12, v13), (v21, v22, v23), ...
ClickHouse는 데이터 앞의 모든 공백과 줄 바꿈 문자 하나(있는 경우)를 제거합니다. 쿼리를 작성할 때는 데이터가 공백으로 시작할 수 있으므로, 쿼리 연산자 뒤에서 줄을 바꿔 새 줄에 데이터를 넣는 것이 좋습니다. 예시:
INSERT INTO t FORMAT TabSeparated
11  Hello, world!
22  Qwerty
command-line client 또는 HTTP 인터페이스를 사용하면 쿼리와 별도로 데이터를 삽입할 수 있습니다.
INSERT 쿼리에 SETTINGS를 지정하려면 FORMAT앞에 지정해야 합니다. FORMAT format_name 뒤의 모든 내용은 데이터로 처리되기 때문입니다. 예시는 다음과 같습니다.
INSERT INTO table SETTINGS ... FORMAT format_name data_set

제약 조건

테이블에 제약 조건이 있으면, 삽입되는 데이터의 각 행에 대해 해당 표현식을 검사합니다. 이 제약 조건 중 하나라도 충족되지 않으면 서버에서 제약 조건 이름과 표현식이 포함된 예외를 발생시키고 쿼리를 중단합니다.

데이터 타입 검증

ClickHouse는 허용된 데이터 타입(enable_time_time64_type, allow_suspicious_low_cardinality_types, allow_suspicious_fixed_string_types 등의 설정으로 제어됨)을 테이블 생성(CREATE TABLE) 및 스키마 수정(ALTER TABLE) 시에만 검증하며, INSERT 시에는 검증하지 않습니다. 즉, 허용되지 않는 데이터 타입을 사용하는 테이블이 이미 존재하면 서버에서 해당 설정이 비활성화되어 있어도 그 테이블에 데이터를 삽입할 수 있습니다. 이는 의도된 동작입니다. 테이블이 한 번 생성된 후에는 타입 생성을 제어하는 설정 때문에 삽입이 차단되지 않아야 합니다. 예시:
SET enable_time_time64_type = 1;

CREATE TABLE events
(
    `id` UInt64,
    `event_time` Time
)
ENGINE = MergeTree()
ORDER BY id;

SET enable_time_time64_type = 0;

-- 설정이 비활성화된 상태에서도 이 구문은 정상적으로 실행됩니다.
-- 테이블이 이미 존재하므로 삽입이 차단되지 않습니다.
INSERT INTO events VALUES (1, '14:30:25');

-- 단, Time 유형으로 새 테이블을 생성하면 실패합니다.
CREATE TABLE events_new
(
    `id` UInt64,
    `event_time` Time
)
ENGINE = MergeTree()
ORDER BY id; -- ERR: TYPE_TIME_TIME64_IS_NOT_ENABLED
따라서 최신 버전의 클라이언트(설정이 기본적으로 활성화된 상태)는 대상 테이블에 해당 컬럼 타입이 이미 있는 경우, 더 오래된 버전의 서버(설정이 비활성화된 상태)에 허용되지 않는 데이터 타입의 데이터를 삽입할 수 있습니다. 검증은 DML 수준이 아니라 DDL 수준에서 수행됩니다.

SELECT 결과 삽입

구문
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] SELECT ...
컬럼은 SELECT 절에서의 위치에 따라 매핑됩니다. 하지만 SELECT 표현식에서의 이름과 INSERT 대상 테이블의 이름은 서로 다를 수 있습니다. 필요한 경우 타입 변환이 수행됩니다. Values 포맷을 제외한 어떤 데이터 포맷에서도 now(), 1 + 2 등과 같은 표현식을 값으로 지정할 수 없습니다. Values 포맷에서는 표현식을 제한적으로 사용할 수 있지만, 이 경우 해당 표현식을 실행할 때 비효율적인 코드가 사용되므로 권장하지 않습니다. 데이터 파트를 수정하는 다른 쿼리는 지원되지 않습니다: UPDATE, DELETE, REPLACE, MERGE, UPSERT, INSERT UPDATE. 하지만 ALTER TABLE ... DROP PARTITION을 사용하여 오래된 데이터를 삭제할 수 있습니다. SELECT 절에 테이블 함수 input()가 포함된 경우, FORMAT 절은 쿼리의 마지막에 지정해야 합니다. 널을 허용하지 않는 데이터 타입의 컬럼에 NULL 대신 기본값을 삽입하려면 insert_null_as_default 설정을 활성화하십시오. INSERT는 CTE(common table expression)도 지원합니다. 예를 들어, 다음 두 SQL 문은 동일합니다:
INSERT INTO x WITH y AS (SELECT * FROM numbers(10)) SELECT * FROM y;
WITH y AS (SELECT * FROM numbers(10)) INSERT INTO x SELECT * FROM y;

파일에서 데이터 삽입하기

구문
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] FROM INFILE file_name [COMPRESSION type] [SETTINGS ...] [FORMAT format_name]
위 구문을 사용하면 클라이언트 측에 저장된 파일 하나 또는 여러 파일에서 데이터를 삽입할 수 있습니다. file_nametype은 문자열 리터럴입니다. 입력 파일 포맷FORMAT 절에서 지정해야 합니다. 압축 파일도 지원됩니다. 압축 유형은 파일 이름의 확장자를 기준으로 감지됩니다. 또는 COMPRESSION 절에서 명시적으로 지정할 수도 있습니다. 지원되는 유형은 다음과 같습니다: 'none', 'gzip', 'deflate', 'br', 'xz', 'zstd', 'lz4', 'bz2'. 이 기능은 command-line clientclickhouse-local에서 사용할 수 있습니다. 예시

FROM INFILE을 사용한 단일 파일

command-line client를 사용해 다음 쿼리를 실행하십시오:
Query
echo 1,A > input.csv ; echo 2,B >> input.csv
clickhouse-client --query="CREATE TABLE table_from_file (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;"
clickhouse-client --query="INSERT INTO table_from_file FROM INFILE 'input.csv' FORMAT CSV;"
clickhouse-client --query="SELECT * FROM table_from_file FORMAT PrettyCompact;"
Response
┌─id─┬─text─┐
│  1 │ A    │
│  2 │ B    │
└────┴──────┘

글롭 패턴을 사용해 FROM INFILE로 여러 파일 처리하기

이 예시는 이전 예시와 매우 유사하지만, FROM INFILE 'input_*.csv'를 사용해 여러 파일에서 삽입을 수행합니다.
echo 1,A > input_1.csv ; echo 2,B > input_2.csv
clickhouse-client --query="CREATE TABLE infile_globs (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;"
clickhouse-client --query="INSERT INTO infile_globs FROM INFILE 'input_*.csv' FORMAT CSV;"
clickhouse-client --query="SELECT * FROM infile_globs FORMAT PrettyCompact;"
*를 사용해 여러 파일을 선택하는 것 외에도, 범위({1,2} 또는 {1..9})와 기타 글롭 치환을 사용할 수 있습니다. 다음 세 가지 방법은 모두 위의 예시에 사용할 수 있습니다:
INSERT INTO infile_globs FROM INFILE 'input_*.csv' FORMAT CSV;
INSERT INTO infile_globs FROM INFILE 'input_{1,2}.csv' FORMAT CSV;
INSERT INTO infile_globs FROM INFILE 'input_?.csv' FORMAT CSV;

테이블 함수를 사용한 삽입

데이터는 테이블 함수로 참조되는 테이블에 삽입할 수 있습니다. 구문
INSERT INTO [TABLE] FUNCTION table_func ...
예시 다음 쿼리에서는 remote 테이블 함수를 사용합니다:
Query
CREATE TABLE simple_table (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;
INSERT INTO TABLE FUNCTION remote('localhost', default.simple_table)
    VALUES (100, 'inserted via remote()');
SELECT * FROM simple_table;
Response
┌──id─┬─text──────────────────┐
│ 100 │ inserted via remote() │
└─────┴───────────────────────┘

ClickHouse Cloud에 삽입하기

기본적으로 ClickHouse Cloud의 서비스는 고가용성을 위해 여러 레플리카를 제공합니다. 서비스에 연결하면 이러한 레플리카 중 하나에 연결됩니다. INSERT가 성공하면 데이터가 기본 스토리지에 기록됩니다. 하지만 레플리카가 이러한 업데이트를 수신하는 데는 다소 시간이 걸릴 수 있습니다. 따라서 다른 연결을 사용해 다른 레플리카 중 하나에서 SELECT 쿼리를 실행하면 업데이트된 데이터가 아직 반영되지 않았을 수 있습니다. select_sequential_consistency를 사용하면 레플리카가 최신 업데이트를 강제로 수신하도록 할 수 있습니다. 다음은 이 설정을 사용하는 SELECT 쿼리의 예시입니다.
SELECT .... SETTINGS select_sequential_consistency = 1;
select_sequential_consistency를 사용하면 ClickHouse Keeper(ClickHouse Cloud에서 내부적으로 사용됨)에 가해지는 부하가 증가하며, 서비스 부하에 따라 성능이 저하될 수 있습니다. 꼭 필요한 경우가 아니라면 이 설정은 활성화하지 않는 것이 좋습니다. 권장되는 방법은 동일한 session에서 읽기/쓰기를 수행하거나, 네이티브 프로토콜을 사용하는 클라이언트 드라이버(즉, 고정 연결을 지원하는 드라이버)를 사용하는 것입니다.

복제된 구성에 데이터 삽입

복제된 구성에서는 데이터가 복제된 뒤 다른 레플리카에 표시됩니다. 데이터 복제는 INSERT 직후 바로 시작되며(즉, 다른 레플리카에서 다운로드됨), 이 동작은 ClickHouse Cloud와 다릅니다. ClickHouse Cloud에서는 데이터가 즉시 공유 스토리지에 기록되고, 레플리카는 메타데이터 변경 사항을 구독합니다. 복제된 구성에서는 분산 합의를 위해 ClickHouse Keeper에 커밋해야 하므로 INSERTs에 상당한 시간(약 1초)이 걸릴 수 있다는 점에 유의하십시오. 또한 스토리지로 S3를 사용하면 지연 시간이 추가로 늘어납니다.

성능 고려 사항

INSERT는 입력 데이터를 기본 키(primary key)로 정렬하고, 파티션 키(partition key)를 기준으로 파티션으로 나눕니다. 여러 파티션에 데이터를 한 번에 삽입하면 INSERT 쿼리 성능이 크게 저하될 수 있습니다. 이를 방지하려면 다음을 수행하세요:
  • 한 번에 100,000행 정도의 비교적 큰 배치로 데이터를 추가합니다.
  • ClickHouse에 업로드하기 전에 파티션 키를 기준으로 데이터를 그룹화합니다.
다음 경우에는 성능이 저하되지 않습니다:
  • 데이터가 실시간으로 추가되는 경우
  • 일반적으로 시간순으로 정렬된 데이터를 업로드하는 경우

비동기 삽입

작지만 빈번한 삽입 작업에서도 데이터를 비동기적으로 삽입할 수 있습니다. 이렇게 삽입된 데이터는 배치로 묶인 다음 안전하게 테이블에 삽입됩니다. 비동기 삽입을 사용하려면 async_insert 설정을 활성화하십시오. async_insert 또는 Buffer 테이블 엔진을 사용하면 추가 버퍼링이 발생합니다.

대용량 또는 장시간 실행되는 삽입

대량의 데이터를 삽입할 때 ClickHouse는 “squashing”이라는 과정을 통해 쓰기 성능을 최적화합니다. 메모리에 있는 작은 데이터 블록은 디스크에 기록되기 전에 머지되어 더 큰 블록으로 합쳐집니다. squashing은 각 쓰기 작업에 수반되는 오버헤드를 줄여줍니다. 이 과정에서 삽입된 데이터는 ClickHouse가 각 max_insert_block_size개의 행을 기록한 후 쿼리할 수 있습니다. 관련 항목
마지막 수정일 2026년 6월 10일