Вставка данных: батчи, async insert, почему нельзя по одной строке

↑ 3.1 ClickHouse · ← Предыдущая · → Следующая

Желательно~3 мин чтенияУровень: middle

Зачем это на собесе

Самая частая ошибка новичков: вставка построчно. Нужно знать причины и решения.

Почему нельзя по одной строке

Каждый INSERT создаёт отдельный парт на диске. Тысячи мелких вставок в секунду → тысячи партов → фоновые слияния не успевают → ошибка Too many parts, деградация чтения (нужно открывать много файлов), нагрузка на Keeper при репликации.

Правило: вставляйте большими пачками — минимум тысячи строк, лучше 10–100 тыс. и более за вставку, не чаще 1 раза в секунду на таблицу (ориентир).

Способы

Батчи на стороне клиента

INSERT INTO events FORMAT JSONEachRow
{"event_time":"2026-09-30 12:00:00","user_id":1,"event_type":"click"}
{"event_time":"2026-09-30 12:00:01","user_id":2,"event_type":"view"}

Форматы: Native (самый быстрый), RowBinary, CSV, JSONEachRow, Parquet, ArrowStream. Клиентские библиотеки: ClickHouse.Client (.NET), clickhouse-go, clickhouse-connect (Python).

Асинхронные вставки (async_insert)

Сервер сам накапливает мелкие вставки в буфер и записывает одним пактом:

SET async_insert = 1, wait_for_async_insert = 1;
INSERT INTO events VALUES (...);

Настройки: async_insert_max_data_size, async_insert_busy_timeout_ms. wait_for_async_insert = 1 — клиент получает подтверждение после записи (надёжнее), 0 — быстрее, но при сбое возможна потеря.

Промежуточные буферы и очереди

  • Kafka Engine / Kafka Connect / Vector / Fluent Bit / Redpanda Connect собирают батчи;
  • Buffer-таблица (устаревающий подход);
  • буферизация на стороне приложения (пакет по размеру или времени).

Идемпотентность и повторы

Для реплицируемых таблиц ClickHouse дедуплицирует повторную вставку того же блока (insert_deduplicate, окно последних блоков replicated_deduplication_window). Повтор вставки идентичных данных и порядка безопасен. Для надёжной доставки используйте одинаковые батчи при повторах (insert_deduplication_token).

Эффективность

  • сортировка данных батча по ключу не обязательна, но упрощает;
  • вставка в несколько партиций одним батчем создаёт по парту на партицию: ограничивайте (max_partitions_per_insert_block);
  • используйте Native/сжатие, параллельные вставки в разные шарды/реплики;
  • массовая загрузка: INSERT SELECT, clickhouse-local, s3() табличная функция.
INSERT INTO events SELECT * FROM s3('https://bucket/data/*.parquet', 'Parquet');

Мониторинг

SELECT table, count() AS parts, sum(rows) FROM system.parts WHERE active GROUP BY table;
SELECT * FROM system.part_log ORDER BY event_time DESC LIMIT 10;

Настройки: parts_to_delay_insert, parts_to_throw_insert.

Вопросы с ответами