Ingestion and Integrations
This domain covers getting data in without creating a part explosion: batch sizing, formats, deduplication on retries, streaming engines, file and object-storage ingestion, materialized views as pipelines, and Cloud-specific tooling. Questions usually describe a pipeline and ask what breaks under retry, restart, or high insert frequency.
Batching and formats
- Never insert row-by-row. Target at least ~1,000 rows per INSERT, and commonly 10k–100k+; each INSERT creates a part, and many small parts stall merges.
Nativeis the fastest format for ClickHouse-to-ClickHouse transfers;RowBinaryis compact;JSONEachRowis the convenient HTTP/streaming default;TSV/CSVparse cheaply;Parquetsuits files.input_format_skip_unknown_fields = 1tolerates schema drift;input_format_null_as_default = 1avoids NULL-type surprises.async_insert = 1withwait_for_async_insert = 1lets the server coalesce many small client inserts into fewer parts.
Idempotent retries
insert_deduplicate = 1(default for Replicated tables) hashes each inserted block; resending the identical block is ignored. It only works if the client retries with byte-identical batch content and size, and it is not available on plain non-replicated MergeTree.
Streaming and external sources
- The
Kafkatable engine is a consumer: pair it with a materialized view that reads from the Kafka table and writes into a MergeTree table. The MV fires on inserts into its source table and never backfills. - ClickHouse Cloud does not expose the Kafka engine; use ClickPipes instead. ClickPipes also covers object storage ingestion.
s3()table function for ad hoc reads,S3Queueengine for continuous file pickup,S3engine for repeatable queries.- Refreshable materialized views (
REFRESH EVERY ...) recompute a target table on a schedule rather than per insert. - Dictionaries provide low-latency lookup enrichment via
dictGet.
Worked example
Kafka topic of JSON events to a deduplicated table:
CREATE TABLE kafka_q ENGINE = Kafka SETTINGS kafka_broker_list='...', kafka_topic_list='events', kafka_group_name='ch', kafka_format='JSONEachRow'CREATE TABLE events (...) ENGINE = ReplacingMergeTree ORDER BY event_idCREATE MATERIALIZED VIEW mv TO events AS SELECT ... FROM kafka_qOffsets commit after the block is written, so a crash in between can replay a batch - ReplacingMergeTree absorbs the duplicates.
Traps that cost marks
SELECT * FROM kafka_qconsumes messages instead of inspecting them.- Expecting a materialized view to populate historical rows.
- Retrying inserts with re-serialized, non-identical batches and expecting deduplication.