clickhouse/clickhouse
Async insert
async_insert=1 lets the server batch small inserts on the server side. Without it, every INSERT becomes a part — bad for MergeTree (creates fragmentation) and Keeper load (each replicated insert is a Keeper transaction). With it, the server accumulates rows from many concurrent clients and flushes them as a single bigger part.
Where it lives
src/Interpreters/AsynchronousInsertQueue.cpp— the queue, hashing, and flush logic.src/Interpreters/InterpreterInsertQuery.cpp— entry point that branches between sync and async paths.src/Interpreters/Context.cpp— exposes the queue.src/Storages/MergeTree/MergeTreeSink.cpp— the eventual writer.
Behaviour
When async_insert=1:
- The
INSERTblocks the client only until the row data is parsed and acknowledged into the queue (a few milliseconds). - The queue groups rows by
(table, settings, format)— different settings produce different batches. - A batch is flushed when either of:
- it reaches
async_insert_max_data_sizebytes (default 10 MiB), or - it reaches
async_insert_busy_timeout_msmilliseconds since the first row landed (default 1 second).
- it reaches
- The flush creates exactly one part per batch.
- With
wait_for_async_insert=1, the original client waits for the flush; with=0, the client gets an ack as soon as the rows are queued (best for sustained streaming workloads but no end-to-end durability guarantee).
Adaptive timeouts
async_insert_use_adaptive_busy_timeout=1 (the default) ramps the busy timeout up and down based on incoming rate so that bursty traffic still gets quick flushes while idle traffic doesn't waste resources.
Deduplication
Async inserts participate in MergeTree's standard deduplication: identical batches (same hash) are deduped within replicated_deduplication_window. The "token" can be set per-insert via async_insert_deduplication_token.
Stack token
Each batch flush yields a single MergeTree part. The relationship is preserved in system.asynchronous_insert_log so that you can correlate INSERT calls to the resulting part name and timing.
Diagnostics
system.asynchronous_inserts— current in-flight queue.system.asynchronous_insert_log— historical flushes (one row per batch, with all clients in the batch inquery_ids).system.metrics—AsynchronousInsertThreadsActive,AsynchronousInsertQueueSize.
Settings
| Setting | Default | Effect |
|---|---|---|
async_insert |
0 |
Toggle. |
wait_for_async_insert |
1 |
Wait for flush before ack. |
wait_for_async_insert_timeout |
120 s |
Cap on the wait. |
async_insert_max_data_size |
10 MiB |
Flush threshold by size. |
async_insert_busy_timeout_ms |
1000 ms |
Flush threshold by time. |
async_insert_use_adaptive_busy_timeout |
1 |
Adaptive timeout. |
async_insert_max_query_number |
450 |
Max queries per batch. |
async_insert_deduplication_token |
'' |
Manual dedup token. |
async_insert_threads |
16 |
Background workers. |
When to use it
- Many small inserts per second from many clients (often the case when ingesting from a queue, IoT, log shippers).
- Cannot batch on the client side (e.g. behind an HTTP gateway).
When you can batch on the client side (every few seconds, every few MiB), do that instead — async insert adds queue and observability cost on the server.
Related pages
- MergeTree — eventual destination of the flushed part.
- Replicated MergeTree — replication is separate from async insert; both compose.
- Server protocols — the HTTP and native handlers branch into the queue.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.