Skip to main content
Операции вставки иногда могут завершаться с ошибками, например из-за тайм-аутов. При сбое вставки данные могли быть успешно вставлены, а могли и не быть. В этом руководстве рассказывается, как работает дедупликация при повторных попытках вставки, чтобы одни и те же данные не вставлялись больше одного раза. При повторной попытке вставки ClickHouse пытается определить, были ли данные уже успешно вставлены. Если вставленные данные помечены как дубликат, ClickHouse не вставляет их в целевую таблицу. Однако пользователь всё равно получит статус успешного выполнения операции, как если бы данные были вставлены обычным образом. Дедупликация охватывает синхронные вставки, асинхронные вставки и запросы INSERT ... SELECT. Один параметр, deduplicate_insert, управляет синхронными и асинхронными вставками. Для INSERT ... SELECT требуется особое внимание, и у него есть собственный параметр. См. Параметры, управляющие дедупликацией вставок.

Ограничения

Неопределённый статус вставки

Пользователь должен повторять операцию вставки, пока она не завершится успешно. Если все повторные попытки окажутся неудачными, определить, были ли данные вставлены, невозможно. Если задействованы materialized views, также неясно, в каких таблицах могли появиться данные. Materialized views могут быть рассинхронизированы с исходной таблицей.

Ограничение окна дедупликации

Если в ходе последовательности повторных попыток выполняется более *_deduplication_window других операций вставки, дедупликация может работать не так, как задумано. В этом случае одни и те же данные могут быть вставлены несколько раз.

Настройки, управляющие дедупликацией вставок

ClickHouse выполняет дедупликацию вставки только при соблюдении обоих следующих условий:
  1. Целевая таблица хранит журнал дедупликации. Это настройка уровня таблицы.
  2. Для запроса включена дедупликация. Это настройка уровня запроса.

Настройки уровня таблицы

Только движки *MergeTree поддерживают дедупликацию при вставке. Для движков *ReplicatedMergeTree журнал дедупликации включен по умолчанию и управляется настройками replicated_deduplication_window и replicated_deduplication_window_seconds. Для нереплицируемых движков *MergeTree журнал управляется настройкой non_replicated_deduplication_window, которая по умолчанию имеет значение 0. Поэтому обычная таблица MergeTree не выполняет дедупликацию, пока вы не зададите для этого окна положительное значение. Перечисленные выше настройки определяют параметры журнала дедупликации таблицы. Журнал дедупликации хранит конечное число block_id, которые определяют, как работает дедупликация (см. ниже).
replicated_deduplication_window_for_async_inserts и replicated_deduplication_window_seconds_for_async_inserts — устаревшие настройки. Синхронные и асинхронные вставки теперь используют один журнал дедупликации, поэтому replicated_deduplication_window управляет обеими. Устаревшие настройки ограничивали размер старого каталога ClickHouse Keeper, что важно при поэтапном обновлении.

Настройки на уровне запроса

deduplicate_insert принимает три значения:
  • enable — дедупликация включена для запроса INSERT.
  • disable — дедупликация отключена для запроса INSERT.
  • backward_compatible_choice — решение передаётся устаревшим настройкам insert_deduplicate (синхронные вставки) и async_insert_deduplicate (асинхронные вставки).
Обратите внимание: запрос, выполняемый с deduplicate_insert = disable, не записывает block_id для своих блоков. Такие данные нельзя дедуплицировать позднее, даже если повторить вставку с deduplicate_insert = enable. То же относится к случаям, когда целевая таблица не хранит журнал дедупликации: ничего не записывается, поэтому при повторной попытке сопоставить данные будет не с чем.

Старшинство

  1. Для запроса INSERT ... SELECT определяющим является параметр deduplicate_insert_select. См. Дедупликация для INSERT … SELECT.
  2. Для всех остальных операций INSERT определяющим является параметр deduplicate_insert.
  3. Параметры insert_deduplicate и async_insert_deduplicate учитываются только при значении backward_compatible_choice параметра deduplicate_insert.

Устаревшие и упразднённые настройки

Начиная с версии 26.2, значением по умолчанию для deduplicate_insert является enable. Поэтому настройка insert_deduplicate = 0 больше сама по себе не отключает дедупликацию. Чтобы отключить дедупликацию, установите deduplicate_insert = disable.
В версии 26.2 также были изменены значения по умолчанию для async_insert и deduplicate_blocks_in_dependent_materialized_views: теперь они включены. Настройка compatibility управляет всеми тремя настройками. Если установить для compatibility версию ранее 26.2, эти настройки сохранят прежние значения по умолчанию: для deduplicate_insert будет установлено backward_compatible_choice, и выбор будет передан insert_deduplicate и async_insert_deduplicate. Явно заданная настройка всегда применяется и не зависит от compatibility.

Как работает дедупликация при вставке

Когда данные вставляются в ClickHouse, система разбивает их на блоки в зависимости от количества строк и байтов. Для таблиц, использующих движки *MergeTree, каждому блоку присваивается уникальный block_id — хеш данных в этом блоке. Этот block_id используется как уникальный ключ операции вставки. Если такой же block_id найден в журнале дедупликации, блок считается дубликатом и не вставляется в таблицу. Этот подход хорошо работает, когда вставки содержат разные данные. Однако если одни и те же данные намеренно вставляются несколько раз, нужно использовать настройку insert_deduplication_token, чтобы управлять процессом дедупликации. Эта настройка позволяет указать уникальный токен для каждой вставки, который ClickHouse использует для определения, являются ли данные дубликатом. insert_deduplication_token имеет более высокий приоритет: если указан токен, ClickHouse не использует хеш-сумму данных. Для запросов INSERT ... VALUES разбиение вставляемых данных на блоки детерминировано и задаётся настройками. Поэтому повторные попытки вставки следует выполнять с теми же значениями настроек, что и в исходной операции.

Дедупликация для INSERT ... SELECT

Для запросов INSERT ... SELECT часть SELECT должна при каждой попытке возвращать одни и те же данные в одном и том же порядке. В противном случае блоки и их block_id будут различаться, поэтому повторная попытка не будет распознана как дубликат. ClickHouse не может проверить, что исходные данные не изменились, но может определить, даёт ли сам запрос воспроизводимый результат. SELECT считается стабильным, если выполняются оба следующих условия:
  • Запрос содержит предложение ORDER BY ALL. Распознаётся только точная конструкция ORDER BY ALL. Обычный ORDER BY <expressions> не распознаётся, а UNION из двух или более SELECT никогда не считается стабильным.
  • Конвейер чтения завершается одним потоком.
Непустой insert_deduplication_token — равноценная замена стабильности, поскольку в этом случае вставку идентифицирует токен, а не данные. Настройка deduplicate_insert_select определяет поведение: enable_when_possible и enable_even_for_bad_queries также учитывают deduplicate_insert: если оно имеет значение disable, запрос не дедуплицируется. force_enable переопределяет deduplicate_insert. Помните, что выбранная таблица может обновиться между повторными попытками. В этом случае два подхода дают противоположный результат:
  • Без insert_deduplication_token значения block_id вычисляются на основе данных. Изменённый результат создаёт другие block_id, дедупликация не выполняется, и повторная попытка вставляет новые данные поверх всего, что уже было записано при первой попытке.
  • С insert_deduplication_token вставку идентифицирует только токен. Повторная попытка распознаётся как дубликат и отбрасывается, даже если она вставила бы другие данные.
Выберите подход в соответствии с тем, какой смысл должна иметь повторная попытка. Кроме того, при вставке больших объёмов данных количество блоков может превысить размер окна журнала дедупликации, и ClickHouse не сможет дедуплицировать эти блоки.

Дедупликация асинхронных вставок

Асинхронные вставки (async_insert, включенные по умолчанию с версии 26.2) дедуплицируются при повторных попытках так же, как синхронные вставки. Обоими типами управляет параметр deduplicate_insert, поэтому отдельный переключатель не нужен. Оба типа вставок также используют общий журнал дедупликации и одинаково вычисляют block_id. Поэтому можно переключать клиент между синхронными и асинхронными вставками, не нарушая дедупликацию: повторная попытка, отправленная в одном режиме, всё равно будет распознана как дубликат попытки, отправленной в другом. Перевод рабочей нагрузки с синхронных на асинхронные вставки также безопасен для таблицы, использующей дедупликацию.
До версии 26.2 дедупликация асинхронных вставок по умолчанию была отключена и управлялась параметром async_insert_deduplicate. Теперь этот параметр учитывается только при значении backward_compatible_choice параметра deduplicate_insert.

Гранулярность дедупликации

Сервер объединяет несколько асинхронных вставок в один батч и записывает его в виде одной или нескольких частей — как минимум по одной для каждого уникального значения ключа партиционирования. Дедупликация выполняется для каждого пользовательского запроса, а не для батча:
  • Каждый запрос в очереди добавляет в батч один токен дедупликации.
  • Токен — это либо значение insert_deduplication_token, если оно задано в запросе, либо хеш строк, добавленных этим запросом.
  • Объединение в батчи не влияет на токены, а insert_deduplication_token не влияет на группировку запросов в батчи.
Это приводит к двум последствиям:
  • Если один из запросов в батче является дубликатом, ClickHouse удаляет только строки этого запроса. Остальные данные из батча вставляются как обычно. Часть полностью пропускается только в том случае, если из неё удалены все строки.
  • Если два запроса в одном батче имеют одинаковый токен, второй отбрасывается до записи части. Это применяется отдельно для каждой партиции: если два запроса записывают строки в разные партиции, оба сохраняются.
События DuplicatedAsyncInserts и SelfDuplicatedAsyncInserts в system.events учитывают эти два случая.

Асинхронные вставки и materialized view

Дедупликация асинхронных вставок работает совместно с зависимыми materialized view. Правило простое: один блок на входе — один блок на выходе. Если внутренний запрос представления преобразует один входной блок в один выходной, дедупликация работает. Если представление формирует второй блок, ClickHouse генерирует исключение NOT_IMPLEMENTED. Представление формирует второй блок, когда его результат уже не помещается в один блок. max_block_size задаёт количество строк, помещающихся в блок. Преобразования столбцов, фильтрация и агрегация никогда не добавляют строк, поэтому всегда остаются в одном блоке. JOIN может добавлять строки. Он работает, пока результат не превышает max_block_size, и завершается ошибкой при превышении этого значения. Чтобы выполнять вставку через представление, формирующее более одного блока, либо установите deduplicate_blocks_in_dependent_materialized_views = 0, либо используйте синхронные вставки.

Дедупликация при вставке с materialized view

Если у таблицы есть одно или несколько materialized view, вставляемые данные также записываются в целевые таблицы этих представлений с заданными преобразованиями. Преобразованные данные тоже дедуплицируются при повторных попытках. ClickHouse выполняет дедупликацию для materialized view так же, как и для данных, вставляемых в целевую таблицу. Управлять этим процессом можно с помощью следующих настроек исходной таблицы: Дедупликация в таблицах materialized view дополнительно регулируется настройкой профиля пользователя deduplicate_blocks_in_dependent_materialized_views, которая включена по умолчанию начиная с версии 26.2. Для дедупликации должны быть включены оба параметра: deduplicate_insert дедуплицирует данные, вставляемые в исходную таблицу, а deduplicate_blocks_in_dependent_materialized_views дополнительно дедуплицирует данные в зависимых таблицах. Для полной дедупликации включите оба параметра. При вставке блоков в таблицы materialized view ClickHouse вычисляет block_id, хешируя строку, которая объединяет block_id исходной таблицы и дополнительные идентификаторы. Это обеспечивает точную дедупликацию в materialized view и позволяет различать данные по их исходной вставке независимо от преобразований, применённых до записи в целевую таблицу materialized view.

Примеры

Идентичные блоки после преобразований в materialized view

Идентичные блоки, сгенерированные при преобразовании внутри materialized view, не дедуплицируются, поскольку они основаны на разных вставленных данных. Вот пример:
Приведенные выше настройки позволяют выбирать данные из таблицы, состоящей из последовательности блоков, каждый из которых содержит только одну строку. Эти небольшие блоки не объединяются и остаются неизменными, пока не будут вставлены в таблицу. Мы явно задаем дедупликацию в materialized view, хотя по умолчанию она включена:
Здесь мы видим, что в таблицу dst были вставлены две части. 2 блока из select — 2 части при вставке. Эти части содержат разные данные.
Здесь видно, что в таблицу mv_dst было вставлено 2 части. Эти части содержат одни и те же данные, однако дедупликация для них не выполнялась.
Здесь видно, что при повторной вставке все данные дедуплицируются. Дедупликация работает как для таблицы dst, так и для таблицы mv_dst.

Идентичные блоки при вставке

Вставка:
С указанными выше настройками в результате select получаются два блока — следовательно, для вставки в таблицу dst тоже должно быть два блока. Однако мы видим, что в таблицу dst был вставлен только один блок. Это произошло потому, что для второго блока была выполнена дедупликация. В нём те же данные и тот же ключ дедупликации block_id, который вычисляется как хеш от вставленных данных. Такое поведение не соответствует ожидаемому. Такие случаи редки, но теоретически возможны. Чтобы корректно обрабатывать такие ситуации, пользователь должен указать insert_deduplication_token. Исправим это на следующих примерах:

Идентичные блоки при вставке с insert_deduplication_token

Вставка:
Как и ожидалось, были вставлены два идентичных блока.
При повторной вставке, как и ожидалось, выполняется дедупликация.
Эта вставка также будет дедуплицирована, хотя и содержит другие вставленные данные. Обратите внимание, что insert_deduplication_token имеет более высокий приоритет: если указан insert_deduplication_token, ClickHouse не использует хеш-сумму данных.

Разные операции вставки после преобразования создают одинаковые данные в базовой таблице materialized view

Мы каждый раз вставляем разные данные. Однако в таблицу mv_dst вставляются одни и те же данные. Данные не дедуплицируются, потому что исходные данные различались.

Разные варианты вставки через materialized view в одну базовую таблицу с эквивалентными данными

Два одинаковых блока были вставлены в таблицу mv_dst (как и ожидалось).
Для этой повторной попытки выполняется дедупликация в обеих таблицах: dst и mv_dst.
Последнее изменение 26 августа 2026 г.