INSERT 戦略の選び方
効率的なデータのインジェストは、高性能な ClickHouse デプロイメントの基盤となります。適切なデータ挿入戦略を選択することで、スループット、コスト、および信頼性は大きく左右されます。本セクションでは、ワークロードに最適な判断を行うためのベストプラクティス、トレードオフ、および設定オプションについて説明します。
以下の内容は、クライアント経由で ClickHouse にデータをプッシュしていることを前提としています。組み込みのテーブル関数 s3 や gcs などを使用して ClickHouse にデータをプルしている場合は、「S3 への挿入および読み取りパフォーマンスの最適化」ガイドを参照することを推奨します。
デフォルトでは同期インサート
デフォルトでは、ClickHouse へのインサートは同期的に行われます。各インサートクエリは、メタデータおよびインデックスを含むストレージパーツを即座にディスク上に作成します。
そうでない場合は、下記の非同期インサートを参照してください。
以下では、ClickHouse の MergeTree におけるインサートの仕組みを簡単に確認します。

クライアント側のステップ
最適なパフォーマンスのためには、データを①バッチ化する必要があり、バッチサイズが最初の検討事項になります。
ClickHouse はインサートされたデータを、テーブルの主キー列で並べ替えた状態でディスクに格納します。2つ目の検討事項は、サーバーに送信する前にデータを②事前ソートするかどうかです。バッチが主キー列で事前にソートされた状態で届いた場合、ClickHouse はインジェストを高速化するために ⑩ のソートステップを省略できます。
インジェストするデータにあらかじめ決まったフォーマットがない場合、重要な検討事項はフォーマットの選択です。ClickHouse は70 以上のフォーマットでのデータインサートをサポートしています。ただし、ClickHouse のコマンドラインクライアントや各種プログラミング言語のクライアントを使用する際には、この選択はしばしば自動的に処理されます。必要であれば、この自動選択を明示的に上書きすることもできます。
次の主要な検討事項は、ClickHouse サーバーへの送信前にデータを④圧縮するかどうかです。圧縮により転送サイズが減り、ネットワーク効率が向上するため、とくに大規模なデータセットではデータ転送が高速化され、帯域幅使用量も削減されます。
データは⑤ ClickHouse のネットワークインターフェイス、すなわち native または HTTP インターフェイスのいずれかに送信されます(これらはこの記事の後半で比較します)。
サーバー側のステップ
⑥ データを受信したあと、ClickHouse は圧縮が使用されていた場合に ⑦ それを解凍し、その後 ⑧ 元の送信フォーマットからパースします。
そのフォーマット済みデータの値と対象テーブルの DDL ステートメントを用いて、ClickHouse は MergeTree 形式のインメモリブロックを ⑨ 構築し、事前にソートされていない場合は主キー列で行を ⑩ ソートし、⑪ 疎な主キーインデックスを作成し、⑫ 列単位の圧縮を適用し、最後にデータをディスクに ⑬ 書き込み、新しい ⑭ データパーツを作成します。
同期インサートの場合はバッチ化する
The above mechanics illustrate a constant overhead regardless of the insert size, making batch size the single most important optimization for ingest throughput. Batching inserts reduce the overhead as a proportion of total insert time and improves processing efficiency.
We recommend inserting data in batches of at least 1,000 rows, and ideally between 10,000–100,000 rows. Fewer, larger inserts reduce the number of parts written, minimize merge load, and lower overall system resource usage.
For a synchronous insert strategy to be effective this client-side batching is required.
If you're unable to batch data client-side, ClickHouse supports asynchronous inserts that shift batching to the server (see).
Regardless of the size of your inserts, we recommend keeping the number of insert queries around one insert query per second. The reason for this recommendation is that the created parts are merged to larger parts in the background (in order to optimize your data for read queries), and sending too many insert queries per second can lead to situations where the background merging can't keep up with the number of new parts. However, you can use a higher rate of insert queries per second when you use asynchronous inserts (see asynchronous inserts).
冪等なリトライを確保する
同期インサートは冪等でもあります。MergeTree エンジンを使用する場合、ClickHouse はデフォルトでインサートの重複排除を行います。これにより、次のようなあいまいな障害ケースから保護されます。
- インサートは成功したが、ネットワークの中断によりクライアントが応答を受信できなかった。
- インサートがサーバー側で失敗し、タイムアウトした。
いずれの場合も、バッチの内容と順序が同一である限り、インサートをリトライしても安全です。このため、クライアントはデータを変更したり並べ替えたりせず、一貫した方法でリトライすることが極めて重要です。
適切なインサート先を選択する
シャード構成のクラスタでは、次の 2 つの選択肢があります。
- MergeTree または ReplicatedMergeTree テーブルに直接インサートする。これは、クライアントがシャード間でロードバランシングを行える場合に最も効率的なオプションです。
internal_replication = trueの場合、ClickHouse はレプリケーションを透過的に処理します。 - Distributed テーブルにインサートする。これにより、クライアントは任意のノードにデータを送信し、ClickHouse に正しいシャードへの転送を任せることができます。これはよりシンプルですが、追加の転送ステップがあるため、パフォーマンスはわずかに低下します。
internal_replication = trueはこの場合でも推奨されます。
ClickHouse Cloud では、すべてのノードが同一の単一シャードに対して読み書きを行います。INSERT はノード間で自動的に分散されます。ユーザーは公開されたエンドポイントに対して INSERT を送信するだけで構いません。
適切なフォーマットを選択する
ClickHouse における効率的なデータのインジェストには、適切な入力フォーマットの選択が重要です。70 以上のフォーマットがサポートされているため、最も高性能なオプションを選ぶことで、INSERT の速度、CPU およびメモリ使用量、そしてシステム全体の効率に大きな影響を与えられます。
データエンジニアリングやファイルベースのインポートでは柔軟性が有用ですが、アプリケーションではパフォーマンス重視のフォーマットを優先すべきです。
- Native フォーマット(推奨):最も効率的。カラム指向で、サーバー側で必要なパースが最小限。Go および Python クライアントでデフォルトで使用されます。
- RowBinary:効率的な行指向フォーマット。クライアント側でカラム指向への変換が難しい場合に最適。Java クライアントで使用されます。
- JSONEachRow:扱いやすい一方で、パースコストが高いフォーマット。低ボリュームなユースケースや、迅速な連携用途に適しています。
圧縮を使用する
圧縮は、ネットワークオーバーヘッドを削減し、INSERT を高速化し、ClickHouse におけるストレージコストを抑えるうえで重要な役割を果たします。効果的に利用することで、データフォーマットやスキーマを変更することなく、インジェスト性能を向上できます。
INSERT データを圧縮すると、ネットワーク越しに送信されるペイロードサイズが小さくなり、帯域幅の使用量を最小限に抑えつつ、送信を高速化できます。
INSERT において圧縮は、すでに ClickHouse の内部カラムナストレージモデルに整合している Native フォーマットと組み合わせた場合に特に効果的です。この構成では、サーバーはデータを効率的に伸長し、最小限の変換で直接保存できます。
速度重視には LZ4、圧縮率重視には ZSTD を使用する
ClickHouse はデータ送信時に複数の圧縮コーデックをサポートしています。代表的な 2 つの選択肢は次のとおりです。
- LZ4:高速かつ軽量。CPU オーバーヘッドを最小限に抑えつつ、データサイズを大きく削減できるため、高スループットな INSERT に理想的であり、ほとんどの ClickHouse クライアントでデフォルトとして使用されています。
- ZSTD:より高い圧縮率を提供しますが、CPU 負荷が増加します。リージョン間やクラウドプロバイダ間など、ネットワーク転送コストが高いシナリオで有用ですが、クライアント側の計算量とサーバー側の伸長時間がわずかに増加します。
ベストプラクティス:帯域幅が制約されている、またはデータの外向き転送コストが発生する場合を除き、LZ4 を使用してください。そのような場合には ZSTD の利用を検討します。
FastFormats ベンチマーク のテストでは、LZ4 圧縮された Native の INSERT によりデータサイズが 50% 以上削減され、5.6 GiB のデータセットに対してインジェスト時間が 150 秒から 131 秒に短縮されました。ZSTD に切り替えると、同じデータセットは 1.69 GiB まで圧縮されましたが、サーバー側の処理時間はわずかに増加しました。
圧縮によりリソース使用量が削減される
圧縮はネットワークトラフィックを削減するだけでなく、サーバー側の CPU およびメモリ効率も向上させます。圧縮データであれば、ClickHouse が受信するバイト数が少なくなり、大きな入力をパースする時間も短縮されます。この利点は、オブザーバビリティのように多数のクライアントから同時にインジェストを行うシナリオで特に重要です。
圧縮が CPU とメモリに与える影響は、LZ4 の場合は小さく、ZSTD の場合は中程度です。負荷がかかった状態でも、データ量が削減されることでサーバー側の効率は向上します。
圧縮をバッチ処理および効率的な入力フォーマット(Native など)と組み合わせることで、インジェスト性能を最大化できます。
ネイティブインターフェイス(例:clickhouse-client)を使用する場合、LZ4 圧縮はデフォルトで有効になっています。必要に応じて設定により ZSTD に切り替えることもできます。
HTTP インターフェイス を使用する場合は、Content-Encoding ヘッダーを使用して圧縮を適用します(例:Content-Encoding: lz4)。送信前にペイロード全体を圧縮しておく必要があります。
低コストであれば事前ソートを行う
挿入前にデータを主キーで事前ソートしておくと、特に大きなバッチの場合に ClickHouse でのインジェスト効率を向上できます。
事前ソートされたデータが到着すると、ClickHouse はパーツ作成時の内部ソート処理の一部をスキップまたは単純化でき、CPU 使用量を削減しつつ INSERT 処理を高速化できます。事前ソートは圧縮効率も高めます。同種の値がまとまることで、LZ4 や ZSTD のようなコーデックがより良い圧縮率を達成できるためです。これは、大きなバッチ INSERT と圧縮を組み合わせた場合に特に有効で、処理オーバーヘッドと転送データ量の両方を削減します。
とはいえ、事前ソートは必須ではなくオプションの最適化に過ぎません。 ClickHouse は並列処理を用いてデータを非常に効率的にソートでき、多くのケースではサーバー側でソートした方が、クライアント側で事前ソートするよりも高速、あるいは扱いやすい場合があります。
事前ソートは、データがすでにほぼ順序どおりである場合、またはクライアント側リソース(CPU・メモリ)に十分な余裕があり未活用である場合にのみ行うことを推奨します。 オブザーバビリティのようにレイテンシに敏感、あるいは高スループットが求められるユースケースでは、データが順不同で到着したり多数のエージェントから送信されたりするため、多くの場合は事前ソートは行わず、ClickHouse の組み込みパフォーマンスに任せる方が適しています。
非同期 INSERT
Asynchronous inserts in ClickHouse provide a powerful alternative when client-side batching isn't feasible. This is especially valuable in observability workloads, where hundreds or thousands of agents send data continuously—logs, metrics, traces—often in small, real-time payloads. Buffering data client-side in these environments increases complexity, requiring a centralized queue to ensure sufficiently large batches can be sent.
Sending many small batches in synchronous mode is not recommended, leading to many parts being created. This will lead to poor query performance and "too many part" errors.
Asynchronous inserts shift batching responsibility from the client to the server by writing incoming data to an in-memory buffer, then flushing it to storage based on configurable thresholds. This approach significantly reduces part creation overhead, lowers CPU usage, and ensures ingestion remains efficient—even under high concurrency.
The core behavior is controlled via the async_insert setting.

When enabled (1), inserts are buffered and only written to disk once one of the flush conditions is met:
(1) the buffer reaches a specified size (async_insert_max_data_size) (2) a time threshold elapses (async_insert_busy_timeout_ms) or (3) a maximum number of insert queries accumulate (async_insert_max_query_number).
This batching process is invisible to clients and helps ClickHouse efficiently merge insert traffic from multiple sources. However, until a flush occurs, the data cannot be queried. Importantly, there are multiple buffers per insert shape and settings combination, and in clusters, buffers are maintained per node—enabling fine-grained control across multi-tenant environments. Insert mechanics are otherwise identical to those described for synchronous inserts.
Choosing a return mode
The behavior of asynchronous inserts is further refined using the wait_for_async_insert setting.
When set to 1 (the default), ClickHouse only acknowledges the insert after the data is successfully flushed to disk. This ensures strong durability guarantees and makes error handling straightforward: if something goes wrong during the flush, the error is returned to the client. This mode is recommended for most production scenarios, especially when insert failures must be tracked reliably.
Benchmarks show it scales well with concurrency—whether you're running 200 or 500 clients—thanks to adaptive inserts and stable part creation behavior.
Setting wait_for_async_insert = 0 enables "fire-and-forget" mode. Here, the server acknowledges the insert as soon as the data is buffered, without waiting for it to reach storage.
This offers ultra-low-latency inserts and maximal throughput, ideal for high-velocity, low-criticality data. However, this comes with trade-offs: there's no guarantee the data will be persisted, errors may only surface during flush, and it's difficult to trace failed inserts. Use this mode only if your workload can tolerate data loss.
Benchmarks also demonstrate substantial part reduction and lower CPU usage when buffer flushes are infrequent (e.g. every 30 seconds), but the risk of silent failure remains.
Our strong recommendation is to use async_insert=1,wait_for_async_insert=1 if using asynchronous inserts. Using wait_for_async_insert=0 is very risky because your INSERT client may not be aware if there are errors, and also can cause potential overload if your client continues to write quickly in a situation where the ClickHouse server needs to slow down the writes and create some backpressure in order to ensure reliability of the service.
Deduplication and reliability
By default, ClickHouse performs automatic deduplication for synchronous inserts, which makes retries safe in failure scenarios. However, this is disabled for asynchronous inserts unless explicitly enabled (this should not be enabled if you have dependent materialized views—see issue).
In practice, if deduplication is turned on and the same insert is retried—due to, for instance, a timeout or network drop—ClickHouse can safely ignore the duplicate. This helps maintain idempotency and avoids double-writing data. Still, it's worth noting that insert validation and schema parsing happen only during buffer flush—so errors (like type mismatches) will only surface at that point.
Enabling asynchronous inserts
Asynchronous inserts can be enabled for a particular user, or for a specific query:
-
Enabling asynchronous inserts at the user level. This example uses the user
default, if you create a different user then substitute that username: -
You can specify the asynchronous insert settings by using the SETTINGS clause of insert queries:
-
You can also specify asynchronous insert settings as connection parameters when using a ClickHouse programming language client.
As an example, this is how you can do that within a JDBC connection string when you use the ClickHouse Java JDBC driver for connecting to ClickHouse Cloud:
インターフェースを選択する — HTTP かネイティブか
ネイティブ
ClickHouse はデータのインジェスト用に 2 つの主要なインターフェース、ネイティブインターフェース と HTTP インターフェース を提供しており、それぞれにパフォーマンスと柔軟性のトレードオフがあります。clickhouse-client や Go、C++ などの一部の言語クライアントで使用されるネイティブインターフェースは、パフォーマンスを重視して設計されています。常に ClickHouse の高効率な Native 形式でデータを送信し、LZ4 または ZSTD によるブロック単位の圧縮をサポートし、パースやフォーマット変換などの処理をクライアント側にオフロードすることでサーバー側の処理を最小限に抑えます。
さらに、MATERIALIZED および DEFAULT 列値をクライアント側で計算できるため、サーバーはこれらのステップを完全に省略できます。これにより、効率性が重要となる高スループットなインジェストシナリオにおいて、ネイティブインターフェースは理想的な選択となります。
HTTP
多くの従来型データベースとは異なり、ClickHouse は HTTP インターフェースもサポートしています。こちらは対照的に、互換性と柔軟性を優先します。 サポートされている任意の形式 — JSON、CSV、Parquet など — でデータを送信でき、Python、Java、JavaScript、Rust を含むほとんどの ClickHouse クライアントで広くサポートされています。
トラフィックをロードバランサー経由で容易に切り替え・振り分けできるため、これは ClickHouse のネイティブプロトコルより望ましい場合がよくあります。ネイティブプロトコルの方がオーバーヘッドがわずかに少ないため、INSERT パフォーマンスには小さな差が出ると想定されます。
しかし、HTTP インターフェースにはネイティブプロトコルのような深い統合はなく、マテリアライズド値の計算や Native 形式への自動変換といったクライアント側の最適化は行えません。HTTP による挿入でも標準的な HTTP ヘッダー(例: Content-Encoding: lz4)を使って圧縮できますが、圧縮は個々のデータブロックではなくペイロード全体に対して適用されます。このインターフェースは、プロトコルの単純さ、ロードバランシング、幅広い形式との互換性が、生のパフォーマンスよりも重要となる環境で選好されることが多くあります。
これらのインターフェースのより詳細な説明については、こちらを参照してください。