메인 콘텐츠로 건너뛰기

ClickHouse 삽입과 OLTP 데이터베이스의 차이

OLAP(Online Analytical Processing) 데이터베이스인 ClickHouse는 높은 성능과 확장성에 최적화되어 있어 초당 수백만 행까지 삽입할 수 있습니다. 이는 고도로 병렬화된 아키텍처와 효율적인 컬럼 지향 압축이 결합된 결과이지만, 그 대신 즉각적인 일관성은 일부 희생됩니다. 좀 더 구체적으로 말하면, ClickHouse는 append-only 작업에 최적화되어 있으며 최종적 일관성만 보장합니다. 반면 Postgres와 같은 OLTP 데이터베이스는 완전한 ACID 컴플라이언스를 충족하는 트랜잭션 삽입에 특화되어 있어 강한 일관성과 신뢰성을 보장합니다. PostgreSQL은 동시 트랜잭션을 처리하기 위해 MVCC(Multi-Version Concurrency Control)를 사용하며, 이를 위해 데이터의 여러 버전을 유지합니다. 이러한 트랜잭션은 한 번에 소수의 행만 처리하는 경우가 많고, 신뢰성 보장을 위한 상당한 오버헤드가 수반되므로 삽입 성능이 제한될 수 있습니다. 강한 일관성 보장을 유지하면서도 높은 삽입 성능을 얻으려면 ClickHouse에 데이터를 삽입할 때 아래에 설명된 간단한 규칙을 따라야 합니다. 이 규칙을 따르면 사용자가 ClickHouse를 처음 사용할 때 흔히 겪는 문제를 피할 수 있고, OLTP 데이터베이스에서 통하던 삽입 전략을 그대로 복제하려 할 때 생기는 문제도 방지하는 데 도움이 됩니다.

삽입 모범 사례

큰 배치 크기로 삽입하기

기본적으로 ClickHouse에 전송되는 각 삽입은 삽입 데이터와 함께 저장해야 하는 기타 메타데이터를 포함한 스토리지 파트를 즉시 생성합니다. 따라서 각 삽입에 적은 데이터가 들어 있는 많은 수의 삽입을 보내는 것보다, 각 삽입에 더 많은 데이터가 들어 있는 적은 수의 삽입을 보내는 편이 필요한 쓰기 횟수를 줄일 수 있습니다. 일반적으로 한 번에 최소 1,000개 행을 포함하는 비교적 큰 Batch로 데이터를 삽입하는 것을 권장하며, 이상적으로는 10,000개~100,000개 행이 적절합니다. (자세한 내용은 여기를 참조하십시오.) 큰 Batch를 사용할 수 없는 경우 아래에 설명된 비동기 삽입을 사용하십시오.

멱등적 재시도를 위해 일관된 배치를 유지하세요

기본적으로 ClickHouse에 대한 삽입은 동기식이며 멱등적입니다(즉, 동일한 삽입 작업을 여러 번 수행해도 한 번만 수행한 것과 같은 효과가 납니다). MergeTree 엔진 계열의 테이블에서는 ClickHouse가 기본적으로 삽입 시 중복 제거를 자동으로 수행합니다. 즉, 다음과 같은 경우에도 삽입은 안정적으로 처리됩니다.
    1. 데이터를 수신하는 노드에 문제가 있으면 삽입 쿼리가 시간 초과되거나(또는 더 구체적인 오류를 반환하거나) 확인 응답을 받지 못합니다.
    1. 노드가 데이터를 기록했더라도 네트워크 중단으로 인해 쿼리 전송자에게 확인 응답을 반환할 수 없으면, 전송자는 시간 초과 또는 네트워크 오류를 받게 됩니다.
클라이언트 관점에서는 (i)와 (ii)를 구분하기 어려울 수 있습니다. 하지만 두 경우 모두 확인되지 않은 삽입은 즉시 재시도하면 됩니다. 재시도한 삽입 쿼리에 동일한 데이터가 동일한 순서로 포함되어 있기만 하면, 확인되지 않은 원래 삽입이 성공한 경우 ClickHouse는 재시도된 삽입을 자동으로 무시합니다.

MergeTree 테이블 또는 분산 테이블에 삽입

MergeTree(또는 복제된 테이블(Replicated Table))에 직접 삽입하고, 데이터가 세그먼트로 나뉘어 있다면 요청을 여러 노드에 고르게 분산하며, internal_replication=true를 설정하는 것을 권장합니다. 이렇게 하면 ClickHouse가 사용 가능한 레플리카 세그먼트에 데이터를 복제하고, 데이터의 최종 일관성을 보장합니다. 이러한 클라이언트 측 부하 분산이 불편하다면 분산 테이블을 통해 삽입할 수 있으며, 그러면 쓰기가 여러 노드에 분산됩니다. 이 경우에도 internal_replication=true를 설정하는 것이 좋습니다. 다만 이 방식은 쓰기가 먼저 분산 테이블이 있는 노드에 로컬로 수행된 후 세그먼트로 전송되어야 하므로 성능이 다소 떨어집니다.

작은 배치에는 비동기 삽입을 사용하세요

클라이언트 측 배칭이 적합하지 않은 경우가 있습니다. 예를 들어, 단일 목적의 에이전트 수백~수천 개가 로그, 메트릭, 트레이스 등을 전송하는 관측성 사용 사례가 여기에 해당합니다. 이러한 시나리오에서는 문제와 이상 징후를 가능한 한 빨리 감지할 수 있도록 데이터를 실시간으로 전송하는 것이 중요합니다. 또한 관측 대상 시스템에서 이벤트가 급증할 수 있으며, 이 경우 관측성 데이터를 클라이언트 측에서 버퍼링하려고 하면 메모리 사용량이 급증하고 그에 따른 문제가 발생할 수 있습니다. 큰 배치로 삽입할 수 없다면 비동기 삽입을 사용해 ClickHouse에 배칭을 맡길 수 있습니다. 비동기 삽입을 사용하면 아래 다이어그램과 같이 데이터가 먼저 버퍼에 삽입된 다음, 이후 3단계에 걸쳐 데이터베이스 스토리지에 기록됩니다. 비동기 삽입이 활성화되면 ClickHouse는 다음을 수행합니다: (1) 삽입 쿼리를 비동기적으로 수신합니다. (2) 먼저 쿼리 데이터를 메모리 내 버퍼에 기록합니다. (3) 다음 버퍼 플러시가 발생할 때만 데이터를 정렬한 뒤 파트로 데이터베이스 스토리지에 기록합니다. 버퍼가 플러시되기 전에는 동일하거나 다른 클라이언트의 다른 비동기 삽입 쿼리 데이터도 버퍼에 함께 수집될 수 있습니다. 버퍼 플러시로 생성된 파트에는 여러 비동기 삽입 쿼리의 데이터가 포함될 수 있습니다. 일반적으로 이러한 메커니즘은 데이터 배칭을 클라이언트 측에서 서버 측(ClickHouse 인스턴스)으로 옮깁니다.
데이터가 데이터베이스 스토리지로 플러시되기 전까지는 쿼리로 조회할 수 없으며, 버퍼 플러시는 구성할 수 있습니다.비동기 삽입 구성에 대한 전체 세부 사항은 여기에서 확인할 수 있으며, 자세한 설명은 여기에서 확인할 수 있습니다.

공식 ClickHouse 클라이언트 사용

ClickHouse는 가장 널리 사용되는 프로그래밍 언어용 클라이언트를 제공합니다. 이 클라이언트는 데이터가 올바르게 삽입되도록 최적화되어 있으며, 예를 들어 Go client처럼 비동기 삽입을 직접 네이티브로 지원하거나, 쿼리, 사용자 또는 연결 수준 설정에서 활성화된 경우 간접적으로 지원합니다. 사용 가능한 ClickHouse 클라이언트와 드라이버의 전체 목록은 클라이언트 및 드라이버에서 확인하십시오.

네이티브 형식을 우선 사용하십시오

ClickHouse는 삽입(및 쿼리) 시점에 다양한 입력 형식을 지원합니다. 이는 OLTP 데이터베이스와의 중요한 차이점이며, 특히 테이블 함수 및 디스크의 파일에서 데이터를 불러오는 기능과 함께 사용할 때 외부 소스의 데이터를 훨씬 쉽게 적재할 수 있게 해줍니다. 이러한 포맷은 임시 데이터 적재와 데이터 엔지니어링 작업에 적합합니다. 최적의 삽입 성능을 달성하려는 애플리케이션은 Native 형식으로 삽입하는 것이 좋습니다. 이 형식은 대부분의 클라이언트(예: Go, Python)에서 지원되며, 이미 컬럼 지향 형식이므로 서버가 처리해야 하는 작업을 최소화해 줍니다. 이렇게 하면 데이터를 컬럼 지향 형식으로 변환하는 책임이 클라이언트 측에 놓이게 됩니다. 이는 삽입을 효율적으로 스케일링하는 데 중요합니다. 또는 행 기반 형식을 선호한다면 RowBinary format을 사용할 수 있습니다(Java 클라이언트에서 사용). 일반적으로 Native 형식보다 작성하기가 더 쉽습니다. 이 형식은 JSON과 같은 다른 행 기반 형식보다 압축, 네트워크 오버헤드, 서버 처리 측면에서 더 효율적입니다. 빠르게 통합해야 하고 쓰기 처리량이 낮은 경우에는 JSONEachRow 형식도 고려할 수 있습니다. 다만 이 형식은 ClickHouse에서 파싱을 위해 CPU 오버헤드가 발생한다는 점에 유의해야 합니다.

HTTP 인터페이스 사용

많은 기존 데이터베이스와 달리 ClickHouse는 HTTP 인터페이스를 지원합니다. 이를 사용하면 앞서 언급한 어떤 포맷으로든 데이터를 삽입하고 쿼리할 수 있습니다. 이 방식은 로드 밸런서를 통해 트래픽을 쉽게 전환할 수 있으므로 ClickHouse의 네이티브 프로토콜보다 더 적합한 경우가 많습니다. 네이티브 프로토콜은 오버헤드가 약간 더 적으므로 삽입 성능에서 소폭의 차이가 날 수 있습니다. 기존 클라이언트는 이 두 프로토콜 중 하나를 사용하며(경우에 따라 둘 다 사용하기도 합니다. 예: Go client), 네이티브 프로토콜을 사용하면 쿼리 진행 상황도 쉽게 추적할 수 있습니다. 자세한 내용은 HTTP 인터페이스를 참조하십시오.

기본 예시

ClickHouse에서는 익숙한 INSERT INTO TABLE 명령을 사용할 수 있습니다. “ClickHouse에서 테이블 생성하기” 빠른 시작 가이드에서 만든 테이블에 데이터를 삽입해 보겠습니다.
INSERT INTO helloworld.my_first_table (user_id, message, timestamp, metric) VALUES
    (101, 'Hello, ClickHouse!',                                 now(),       -1.0    ),
    (102, 'Insert a lot of rows per batch',                     yesterday(), 1.41421 ),
    (102, 'Sort your data based on your commonly-used queries', today(),     2.718   ),
    (101, 'Granules are the smallest chunks of data read',      now() + 5,   3.14159 )
제대로 적용되었는지 확인하려면 다음 SELECT 쿼리를 실행합니다:
SELECT * FROM helloworld.my_first_table
다음 결과가 반환됩니다:
user_id message                                             timestamp           metric
101         Hello, ClickHouse!                                  2024-11-13 20:01:22     -1
101         Granules are the smallest chunks of data read           2024-11-13 20:01:27 3.14159
102         Insert a lot of rows per batch                          2024-11-12 00:00:00 1.41421
102         Sort your data based on your commonly-used queries  2024-11-13 00:00:00     2.718

Postgres에서 데이터 로드하기

Postgres에서 데이터를 로드할 때는 다음 방법을 사용할 수 있습니다.
  • ClickPipes: PostgreSQL 데이터베이스 복제를 위해 특별히 설계된 ETL 도구입니다. 다음 두 환경에서 모두 사용할 수 있습니다.
  • PostgreSQL 테이블 엔진을 사용해 이전 예시에서처럼 데이터를 직접 읽을 수 있습니다. 일반적으로 timestamp와 같은 알려진 워터마크를 기준으로 한 배치 복제로 충분하거나, 일회성 마이그레이션인 경우에 적합합니다. 이 접근 방식은 수천만 행 규모까지 확장할 수 있습니다. 더 큰 데이터셋을 마이그레이션하려는 경우, 데이터 청크를 각각 처리하는 여러 요청으로 나누는 방식을 고려해야 합니다. 각 청크에 대해 파티션을 최종 테이블로 옮기기 전에 스테이징 테이블을 사용할 수 있습니다. 이렇게 하면 실패한 요청을 재시도할 수 있습니다. 이 대량 로드 전략에 관한 자세한 내용은 여기에서 확인하십시오.
  • PostgreSQL 데이터는 CSV 형식으로 내보낼 수 있습니다. 그런 다음 로컬 파일에서 또는 테이블 함수를 사용해 객체 스토리지를 통해 ClickHouse에 삽입할 수 있습니다.
대용량 데이터셋 삽입에 도움이 필요하신가요?대용량 데이터셋을 삽입하는 데 도움이 필요하거나 ClickHouse Cloud로 데이터를 가져오는 중 오류가 발생하면 support@clickhouse.com으로 문의해 주십시오. 지원해 드립니다.

명령줄에서 데이터 삽입

전제 조건
  • ClickHouse를 설치했습니다
  • clickhouse-server가 실행 중입니다
  • wget, zcat, curl을 사용할 수 있는 터미널이 있습니다
이 예시에서는 배치 모드의 clickhouse-client를 사용해 명령줄에서 CSV 파일을 ClickHouse에 삽입하는 방법을 설명합니다. 배치 모드의 clickhouse-client를 사용해 명령줄로 데이터를 삽입하는 방법에 대한 자세한 정보와 예시는 “Batch mode”를 참조하십시오. 이 예시에서는 Hacker News 데이터셋을 사용합니다. 이 데이터셋에는 Hacker News 데이터 2,800만 행이 포함되어 있습니다.
1

CSV 다운로드

다음 명령을 실행하여 공개 S3 버킷에서 데이터셋의 CSV 버전을 다운로드하십시오:
wget https://datasets-documentation.s3.eu-west-3.amazonaws.com/hackernews/hacknernews.csv.gz
이 압축 파일은 4.6GB 크기이며 2,800만 행을 포함하므로, 다운로드에 5~10분 정도 걸릴 수 있습니다.
2

테이블 생성

clickhouse-server가 실행 중이면, 배치 모드의 clickhouse-client를 사용해 명령줄에서 직접 다음 스키마로 빈 테이블을 생성할 수 있습니다:
clickhouse-client <<'_EOF'
CREATE TABLE hackernews(
    `id` UInt32,
    `deleted` UInt8,
    `type` Enum('story' = 1, 'comment' = 2, 'poll' = 3, 'pollopt' = 4, 'job' = 5),
    `by` LowCardinality(String),
    `time` DateTime,
    `text` String,
    `dead` UInt8,
    `parent` UInt32,
    `poll` UInt32,
    `kids` Array(UInt32),
    `url` String,
    `score` Int32,
    `title` String,
    `parts` Array(UInt32),
    `descendants` Int32
)
ENGINE = MergeTree
ORDER BY id
_EOF
오류가 없다면 테이블이 성공적으로 생성된 것입니다. 위 명령에서는 보간을 방지하기 위해 heredoc 구분자(_EOF)를 작은따옴표로 감쌌습니다. 작은따옴표가 없으면 컬럼 이름을 둘러싼 백틱을 이스케이프해야 합니다.
3

명령줄에서 데이터 삽입

이제 다음 명령을 실행하여 앞에서 다운로드한 파일의 데이터를 테이블에 삽입하십시오:
zcat < hacknernews.csv.gz | ./clickhouse client --query "INSERT INTO hackernews FORMAT CSV"
데이터가 압축되어 있으므로 먼저 gzip, zcat 또는 이와 비슷한 도구로 파일의 압축을 해제한 다음, 압축 해제된 데이터를 적절한 INSERT 문과 FORMAT을 사용해 clickhouse-client로 파이프해야 합니다.
대화형 모드에서 clickhouse-client로 데이터를 삽입할 때는 COMPRESSION 절을 사용해 삽입 시 ClickHouse가 압축 해제를 처리하도록 할 수 있습니다. ClickHouse는 파일 확장자를 기준으로 압축 유형을 자동으로 감지할 수 있으며, 압축 유형을 명시적으로 지정할 수도 있습니다.이 경우 삽입 쿼리는 다음과 같습니다:
clickhouse-client --query "INSERT INTO hackernews FROM INFILE 'hacknernews.csv.gz' COMPRESSION 'gzip' FORMAT CSV;"
데이터 삽입이 완료되면 다음 명령을 실행하여 hackernews 테이블의 행 수를 확인할 수 있습니다:
clickhouse-client --query "SELECT formatReadableQuantity(count(*)) FROM hackernews"
28.74 million
4

curl을 사용해 명령줄에서 데이터 삽입

앞선 단계에서는 먼저 wget을 사용해 CSV 파일을 로컬 머신에 다운로드했습니다. 단일 명령으로 원격 URL에서 직접 데이터를 삽입하는 것도 가능합니다.다음 명령을 실행하여 hackernews 테이블의 데이터를 비우십시오. 그러면 로컬 머신에 다운로드하는 중간 단계 없이 데이터를 다시 삽입할 수 있습니다:
clickhouse-client --query "TRUNCATE hackernews"
이제 다음을 실행하십시오:
curl https://datasets-documentation.s3.eu-west-3.amazonaws.com/hackernews/hacknernews.csv.gz | zcat | clickhouse-client --query "INSERT INTO hackernews FORMAT CSV"
이제 앞서와 같은 명령을 실행해 데이터가 다시 삽입되었는지 확인할 수 있습니다:
clickhouse-client --query "SELECT formatReadableQuantity(count(*)) FROM hackernews"
28.74 million
마지막 수정일 2026년 6월 10일