Open-Source Wikis

/

ClickHouse

/

Features

/

Async insert

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:

  1. The INSERT blocks the client only until the row data is parsed and acknowledged into the queue (a few milliseconds).
  2. The queue groups rows by (table, settings, format) — different settings produce different batches.
  3. A batch is flushed when either of:
    • it reaches async_insert_max_data_size bytes (default 10 MiB), or
    • it reaches async_insert_busy_timeout_ms milliseconds since the first row landed (default 1 second).
  4. The flush creates exactly one part per batch.
  5. 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 in query_ids).
  • system.metricsAsynchronousInsertThreadsActive, 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.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Async insert – ClickHouse wiki | Factory