インサートストラテジーの選択
効率的なデータ取り込みは、高性能のClickHouse展開の基盤を形成します。適切な挿入戦略を選択することで、スループット、コスト、信頼性に大きな影響を与えることができます。このセクションでは、ワークロードに最適な決定を下すためのベストプラクティス、トレードオフ、および設定オプションについて概説します。
以下は、クライアントを介してClickHouseにデータをプッシュすることを想定しています。例えば、s3やgcsなどの組み込みテーブル関数を使用してClickHouseにデータをプルしている場合は、私たちのガイド"S3挿入および読み取りパフォーマンスの最適化"をお勧めします。
デフォルトで同期挿入
デフォルトでは、ClickHouseへの挿入は同期的です。各挿入クエリは即座にディスク上にストレージパーツを作成し、メタデータやインデックスを含みます。
以下にClickHouseのMergeTree挿入メカニクスを簡単に説明します。

クライアント側のステップ
最適なパフォーマンスを得るためには、データを① バッチ処理し、バッチサイズを最初の決定とします。
ClickHouseは挿入されたデータをディスクに、テーブルの主キー列によって順序付けて格納します。2番目の決定は、サーバーへの送信前にデータを②事前にソートするかどうかです。バッチが主キー列によって事前にソートされた状態で到着した場合、ClickHouseは⑨ソートステップをスキップでき、取り込みが迅速になります。
取り込むデータに事前定義された形式がない場合、主要な決定は形式を選択することです。ClickHouseは70以上の形式でデータの挿入をサポートしています。ただし、ClickHouseのコマンドラインクライアントまたはプログラミング言語クライアントを使用する場合、この選択はしばしば自動的に処理されます。必要に応じて、この自動選択を明示的にオーバーライドすることも可能です。
次の主要な決定は、④データをClickHouseサーバーに送信する前に圧縮するかどうかです。圧縮は転送サイズを減少させ、ネットワークの効率を向上させ、特に大規模なデータセットにおいて、より迅速なデータ転送と帯域幅使用量の低下をもたらします。
データは⑤ClickHouseのネットワークインターフェースに転送されます—ネイティブまたはHTTPインターフェースのいずれか(この投稿で後ほど比較します)。
サーバー側のステップ
データを⑥受信した後、ClickHouseは圧縮が使用されている場合は⑦それを解凍し、次に元の送信形式から⑧解析します。
そのフォーマットデータの値とターゲットテーブルのDDLステートメントを使用して、ClickHouseは⑨メモリ内のブロックをMergeTree形式で構築し、もしそれらが事前にソートされていない場合は⑩主キー列で行をソートし、⑪sparse primary indexを作成し、⑫列ごとの圧縮を適用し、⑬データを新しい⑭データパーツとしてディスクに書き込みます。
同期の場合はバッチ挿入
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 that 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).
上記のメカニズムは、挿入サイズに関係なく一定のオーバーヘッドを示しており、バッチサイズがインジェストスループットの最も重要な最適化要素であることを示しています。バッチ挿入は、全体の挿入時間に対するオーバーヘッドを減少させ、処理効率を向上させます。
データは、少なくとも1,000行のバッチで挿入することを推奨し、理想的には10,000〜100,000行の間で行うべきです。少ない大きな挿入は、書き込まれるパーツの数を減少させ、マージ負荷を最小化し、全体的なシステムリソースの使用を低下させます。
同期挿入戦略が効果的に機能するためには、このクライアント側のバッチ処理が必要です。
クライアント側でデータをバッチ処理できない場合、ClickHouseはバッチ処理をサーバーに移す非同期挿入をサポートしています(参照)。
挿入のサイズに関係なく、挿入クエリの数を約1秒あたり1つの挿入クエリに保つことを推奨します。この推奨の理由は、作成されたパーツがバックグラウンドでより大きなパーツにマージされるため(読み取りクエリ用にデータを最適化するため)、1秒あたりに挿入クエリを送信しすぎると、バックグラウンドのマージが新しいパーツの数に追いつけない状況が発生する可能性があるからです。ただし、非同期挿入を使用する場合は、1秒あたりの挿入クエリの頻度を高めることができます(非同期挿入を参照)。
冪等性のあるリトライを確保
同期挿入は冪等性があります。MergeTreeエンジンを使用すると、ClickHouseはデフォルトで挿入を重複排除します。これにより、ネットワーク中断によってクライアントが応答を受け取れなかったなど、不明瞭な障害ケースに対して保護されます。
- 挿入が成功したが、ネットワーク中断によりクライアントが確認を受け取れなかった。
- サーバー側で挿入が失敗し、タイムアウトした。
どちらのケースでも、挿入をリトライするのは安全です - バッチ内容と順序が同じである限り。したがって、クライアントが一貫してリトライし、データを変更または順序を変更しないことが重要です。
正しい挿入ターゲットを選択
シャードクラスターの場合、2つのオプションがあります:
- MergeTreeまたはReplicatedMergeTreeテーブルに直接挿入します。クライアントがシャード間で負荷分散を行える場合、これは最も効率的なオプションです。
internal_replication = true
により、ClickHouseはレプリケーションを透明に処理します。 - Distributed tableに挿入します。これにより、クライアントは任意のノードにデータを送信し、ClickHouseがそれを正しいシャードに転送します。これは単純ですが、追加の転送ステップによりややパフォーマンスが低下します。
internal_replication = true
は引き続き推奨されます。
ClickHouse Cloudでは、すべてのノードが同一の単一シャードに対して読み書きします。挿入はノード間で自動的にバランスされます。ユーザーは単に公開されたエンドポイントに挿入を送信することができます。
正しい形式を選択
効率的なデータ取り込みにおいて、適切な入力形式を選択することが重要です。70以上のサポートされている形式があるため、最もパフォーマンスの高いオプションを選ぶことは、挿入速度、CPUおよびメモリ使用量、全体的なシステム効率に大きな影響を及ぼします。
柔軟性はデータエンジニアリングやファイルベースのインポートに役立ちますが、アプリケーションはパフォーマンス志向の形式を優先すべきです:
- ネイティブ形式(推奨):最も効率的。列指向で、サーバー側で必要な解析が最小限です。デフォルトでGoおよびPythonクライアントで使用されます。
- RowBinary:効率的な行ベースの形式で、カラム指向への変換がクライアント側で難しい場合に最適です。Javaクライアントで使用されます。
- JSONEachRow:使いやすいが解析コストが高いです。低ボリュームのユースケースや迅速な統合に適しています。
圧縮を使用
圧縮は、ネットワークのオーバーヘッドを削減し、挿入を加速し、ClickHouseにおけるストレージコストを低下させる上で重要な役割を果たします。効果的に使用することで、データ形式やスキーマを変更することなく、取り込みパフォーマンスを向上させます。
挿入データを圧縮すると、ネットワーク経由で送信されるペイロードのサイズが減少し、帯域幅使用量が最小化され、伝送が加速されます。
挿入においては、ネイティブ形式で使用すると特に効果的です。この形式はClickHouseの内部の列指向ストレージモデルにすでにマッチしています。この設定では、サーバーは迅速にデータを解凍し、最小限の変換で直接データを保存できます。
スピードにはLZ4を、圧縮率にはZSTDを使用
ClickHouseはデータ転送中にいくつかの圧縮コーデックをサポートしています。一般的なオプションは2つあります:
- LZ4:高速で軽量。CPUオーバーヘッドが最小限で、データサイズを大幅に削減します。高スループットの挿入に最適で、ほとんどのClickHouseクライアントでデフォルトになっています。
- ZSTD:より高い圧縮率を持ちますが、よりCPU集約的です。ネットワーク転送コストが高い場合(地域間やクラウドプロバイダーのシナリオなど)に役立ちますが、クライアント側の計算およびサーバー側の解凍時間をわずかに増加させます。
ベストプラクティス:帯域幅が制約されている場合やデータ流出コストがかかる場合を除き、LZ4を使用してください。その場合はZSTDを検討してください。
FastFormatsベンチマークからのテストでは、LZ4圧縮されたネイティブ挿入がデータサイズを50%以上削減し、5.6 GiBのデータセットに対して取り込み時間を150秒から131秒に短縮しました。ZSTDに切り替えた場合、同じデータセットは1.69 GiBに圧縮されましたが、サーバー側の処理時間はわずかに増加しました。
圧縮はリソース使用量を削減
圧縮はネットワークトラフィックを削減するだけでなく、サーバー上でのCPUおよびメモリの効率も向上させます。圧縮されたデータを使用すると、ClickHouseは少ないバイト数を受け取り、大きな入力の解析に費やす時間も減少します。この利点は、特に可観測性シナリオなど、複数の同時クライアントからの取り込み時に重要です。
LZ4では圧縮によるCPUおよびメモリへの影響は控えめで、ZSTDでは中程度です。負荷がかかっている場合でも、サーバー側の効率はデータ量の減少により改善されます。
圧縮とバッチ処理、効率的な入力形式(ネイティブのような)を組み合わせることで、最良の取り込みパフォーマンスが得られます。
ネイティブインターフェース(例:clickhouse-client)を使用している場合、デフォルトでLZ4圧縮が有効になっています。必要に応じて設定からZSTDに切り替えることができます。
HTTPインターフェースを使用する場合、Content-Encodingヘッダーを使用して圧縮を適用します(例:Content-Encoding: lz4)。全てのペイロードは送信前に圧縮される必要があります。
低コストの場合は事前ソートしてください
挿入の前に主キーでデータを事前にソートすると、特に大規模なバッチにおいて、ClickHouseでの取り込み効率が向上します。
データが事前にソートされた状態で到着すると、ClickHouseはパート作成中に内部ソートステップをスキップまたは簡略化でき、CPU使用量を削減し、挿入プロセスを加速します。事前ソートは、似たような値がまとめられるため、圧縮効率も向上させます。これによりLZ4やZSTDなどのコーデックがより良い圧縮率を達成できます。特に、大規模なバッチ挿入および圧縮と組み合わせると、処理オーバーヘッドと転送データ量の両方を削減するのに役立ちます。
ただし、事前ソートはオプションの最適化であり、必須ではありません。 ClickHouseは並列処理を利用してデータを非常に効率的にソートし、多くの場合、サーバー側のソートはクライアント側の事前ソートよりも速いか、便利です。
データがほぼ順序付けられている、またはクライアント側のリソース(CPU、メモリ)が十分で未使用である場合のみ、事前ソートを推奨します。 遅延に敏感な高スループットのユースケース(可観測性など)では、データが順不同または多数のエージェントから到着するため、事前ソートをスキップし、ClickHouseの内蔵されたパフォーマンスに依存する方がしばしば良いです。
非同期挿入
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.
多くの小さなバッチを同期モードで送信することは推奨されません。これは多くのパーツが作成されることにつながります。これにより、クエリのパフォーマンスが低下し、"too many part" エラーが発生します。
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はデータ取り込みのために、ネイティブインターフェースとHTTPインターフェースの2つの主なインターフェースを提供しています - それぞれパフォーマンスと柔軟性の間でトレードオフがあります。ネイティブインターフェースは、clickhouse-clientやGo、C++などの一部の言語クライアントによって使用され、パフォーマンスのために特別に設計されています。常にClickHouseの非常に効率的なネイティブ形式でデータを送信し、LZ4またはZSTDによるブロック単位の圧縮をサポートし、解析や形式変換などの作業をクライアントにオフロードしてサーバー側の処理を最小限に抑えます。
このインターフェースは、MATERIALIZEDおよびDEFAULT列の値のクライアント側の計算を可能にし、サーバーがこれらのステップを完全にスキップできるようにします。これにより、高スループットの取り込みシナリオに最適です。
HTTP
多くの従来のデータベースとは異なり、ClickHouseはHTTPインターフェースもサポートしています。これに対して、互換性と柔軟性を優先します。 データは任意のサポートされた形式で送信でき、JSON、CSV、Parquetなどを含み、Python、Java、JavaScript、RustなどのほとんどのClickHouseクライアントで広くサポートされています。
これは、トラフィックをロードバランサーで容易に切り替えることができるため、ClickHouseのネイティブプロトコルよりも好まれることがよくあります。ネイティブプロトコルでは、少しだけオーバーヘッドが低い場合、挿入性能に小さな差異が生じると期待しています。
ただし、クライアント側の最適化、例えばマテリアライズされた値の計算やネイティブ形式への自動変換を行うことはできません。HTTP挿入は標準のHTTPヘッダーを使用して圧縮を行うことができますが(例:Content-Encoding: lz4
)、圧縮は個々のデータブロックではなく全ペイロードに適用されます。このインターフェースは、プロトコルのシンプルさ、負荷分散、または広範な形式互換性が生のパフォーマンスよりも重要とされる環境で好まれることがよくあります。
これらのインターフェースの詳細な説明については、こちらをご覧ください。