Learning Platform
Глоссарий Troubleshooting
Урок 02.06 · 25 мин
Средний
INSERTBlockPart CreationAtomic Rename

INSERT Flow

Понимание того, что именно происходит во время INSERT, критически важно для диагностики проблем с производительностью и проектирования эффективных пайплайнов вставки. ClickHouse делает не то, что делают большинство OLTP баз данных.


Шаг за шагом: путь INSERT

INSERT Flow: от клиента до part на диске

Шаг 1: Клиент отправляет INSERT

Клиент: отправляет INSERT данные в одном из форматов ClickHouse. Самые распространённые: Values (SQL синтаксис), JSONEachRow (одна JSON-строка на строку), CSV, TabSeparated. Данные приходят в row-oriented формате — каждая строка содержит все столбцы.
Values / JSONEachRow / CSV

Шаг 2: Parse → колоночный Block

Парсинг и конвертация: ClickHouse разбирает входной формат и преобразует строки в внутренний колоночный блок (Block). Каждый столбец становится непрерывным массивом значений в памяти. Это момент трансформации из row-oriented (по строкам) в column-oriented (по столбцам) представление.

Шаг 3: Сортировка по ORDER BY ключу

Сортировка по ORDER BY: блок сортируется в памяти в соответствии с ORDER BY ключом таблицы. Это объясняет, почему порядок INSERT не важен — ClickHouse всегда пересортирует данные. Сортировка выполняется до записи на диск. Для больших блоков это требует O(N log N) CPU и O(N) RAM.
in-memory sort

Шаг 4: Запись .bin и .mrk2

Запись .bin файлов: для каждого столбца данные сжимаются (по умолчанию LZ4) блоками. Каждый CompressedBlock: заголовок (checksum, method, sizes) + сжатые данные. Параллельно с .bin записывается .mrk2 — файл меток с байтовыми смещениями гранул в .bin.

Шаг 5: Запись метаданных

Запись метаданных: после столбцов пишутся служебные файлы. primary.idx — разреженный индекс (первая строка каждой гранулы). checksums.txt — SHA256 контрольные суммы всех файлов part. count.txt — число строк. columns.txt — список столбцов и типов. partition.dat — значение ключа партиции. minmax_{col}.idx — min/max значения для partition pruning.
primary.idx, checksums, count, columns

Шаг 6: Atomic rename

Atomic rename: весь part записывается во временную директорию (tmp_{part_name}/). После успешной записи всех файлов директория атомарно переименовывается в финальное имя (202401_1_1_0/). Это гарантирует: читатели никогда не видят неполный part. Либо part полностью доступен, либо его нет вовсе.

Шаг 7: Планировщик слияний берёт новый part

Background merge pickup: планировщик слияний замечает новый мелкий part в партиции и добавляет его в список кандидатов на слияние. Если в той же партиции уже есть другие мелкие parts — они будут объединены в фоне. INSERT не ждёт завершения слияния.

Структура Block: единица обработки

Block в ClickHouse — это набор столбцов и счётчик строк. Block — единица обработки в конвейере запросов (query pipeline). Во время INSERT входные данные разбиваются на блоки размером max_insert_block_size (по умолчанию: 1 048 576 строк). Каждый блок создаёт один part на диске.

Один INSERT с 3 000 000 строк при max_insert_block_size=1 048 576:
→ Блок 1 (1 048 576 строк) → part 202401_1_1_0
→ Блок 2 (1 048 576 строк) → part 202401_2_2_0
→ Блок 3 (902 848 строк)   → part 202401_3_3_0
Итого: 3 parts за один INSERT
WARNING

Каждый INSERT создаёт минимум один новый part. При 1000 крошечных INSERTs в секунду (по 1-10 строк) появится 1000 мелких parts — быстрее, чем планировщик слияний успевает их объединять. Пакетируйте INSERT: минимум 1000+ строк за вызов. Используйте async_insert = 1 для автоматического пакетирования на стороне ClickHouse.


Atomic rename: гарантия консистентности

Атомарное переименование — критически важная деталь реализации. Вот почему это работает:

Запись идёт в:   /var/lib/clickhouse/data/default/events/tmp_202401_1_1_0/
  event_date.bin   ← пишется
  user_id.bin      ← пишется
  primary.idx      ← пишется
  checksums.txt    ← пишется
  ...

Все файлы записаны → fsync → atomic rename:
tmp_202401_1_1_0/ → 202401_1_1_0/

Теперь part видят запросы.

На уровне файловой системы rename — атомарная операция (POSIX guarantee). Либо rename завершился и part полностью доступен, либо rename не произошёл и part не виден. Нет промежуточного состояния “part пишется”.

Если сервер упадёт во время записи tmp-директории — tmp-директория остаётся на диске, но не видна запросам (имя начинается с tmp_). При следующем запуске ClickHouse очищает такие директории.


Дедупликация блоков

Для реплицированных таблиц (ReplicatedMergeTree) ClickHouse поддерживает дедупликацию блоков:

  • insert_deduplicate = 1 (по умолчанию для реплицированных таблиц): ClickHouse хэширует каждый блок данных
  • Хеш блока проверяется в ZooKeeper / ClickHouse Keeper
  • Дублирующий блок (с тем же хешем) молча игнорируется
  • Важно для обеспечения exactly-once семантики при at-least-once доставке из Kafka
-- Проверка статуса дедупликации
SELECT event_time, block_id, rows, source_part_name
FROM system.part_log
WHERE table = 'events' AND event_type = 'NewPart'
ORDER BY event_time DESC
LIMIT 20;

Мониторинг INSERT pipeline

TIP

Мониторинг создания parts в реальном времени:

-- Последние created parts
SELECT
    event_time,
    part_name,
    rows,
    size_in_bytes
FROM system.part_log
WHERE table = 'your_table'
  AND event_type = 'NewPart'
ORDER BY event_time DESC
LIMIT 10;

-- Метрики InsertedRows и InsertedBytes
SELECT event, value
FROM system.events
WHERE event IN ('InsertedRows', 'InsertedBytes', 'MergedRows');

Ключевые выводы

  1. INSERT-порядок не важен: ClickHouse пересортирует данные по ORDER BY ключу в памяти перед записью.
  2. Каждый INSERT = минимум один part: большие INSERTs могут создать несколько parts (при превышении max_insert_block_size).
  3. Atomic rename гарантирует консистентность: читатели видят только полные parts — никогда частично написанные.
  4. Block: единица обработки. Один блок = один part на диске. max_insert_block_size = 1 048 576 строк по умолчанию.
  5. Дедупликация блоков — механизм exactly-once для ReplicatedMergeTree при at-least-once поставках из Kafka.
WAL в PostgreSQL: альтернативный подход к durability при записи Batch-обработка: идемпотентность и размер batch

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. На каком шаге обработки INSERT ClickHouse сортирует данные по ключу ORDER BY?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 7