> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-vortex-format.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

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

> Предотвращение дублирования данных при повторных попытках вставки

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

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

Дедупликация охватывает синхронные вставки, асинхронные вставки и запросы `INSERT ... SELECT`. Один параметр, `deduplicate_insert`, управляет синхронными и асинхронными вставками. Для `INSERT ... SELECT` требуется особое внимание, и у него есть собственный параметр. См. [Параметры, управляющие дедупликацией вставок](#settings-that-control-insert-deduplication).

<div id="limitations">
  ## Ограничения
</div>

<div id="uncertain-insert-status">
  ### Неопределённый статус вставки
</div>

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

<div id="deduplication-window-limit">
  ### Ограничение окна дедупликации
</div>

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

<div id="settings-that-control-insert-deduplication">
  ## Настройки, управляющие дедупликацией вставок
</div>

ClickHouse выполняет дедупликацию вставки только при соблюдении обоих следующих условий:

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

<div id="insert-deduplication-for-tables">
  ### Настройки уровня таблицы
</div>

**Только движки `*MergeTree` поддерживают дедупликацию при вставке.**

Для движков `*ReplicatedMergeTree` журнал дедупликации включен по умолчанию и управляется настройками [`replicated_deduplication_window`](/ru/reference/settings/merge-tree-settings/replicated-deduplication-window#replicated_deduplication_window) и [`replicated_deduplication_window_seconds`](/ru/reference/settings/merge-tree-settings/replicated-deduplication-window#replicated_deduplication_window_seconds). Для нереплицируемых движков `*MergeTree` журнал управляется настройкой [`non_replicated_deduplication_window`](/ru/reference/settings/merge-tree-settings/other#non_replicated_deduplication_window), которая по умолчанию имеет значение `0`. Поэтому обычная таблица `MergeTree` не выполняет дедупликацию, пока вы не зададите для этого окна положительное значение.

Перечисленные выше настройки определяют параметры журнала дедупликации таблицы. Журнал дедупликации хранит конечное число `block_id`, которые определяют, как работает дедупликация (см. ниже).

<Note>
  [`replicated_deduplication_window_for_async_inserts`](/ru/reference/settings/merge-tree-settings/replicated-deduplication-window#replicated_deduplication_window_for_async_inserts) и [`replicated_deduplication_window_seconds_for_async_inserts`](/ru/reference/settings/merge-tree-settings/replicated-deduplication-window#replicated_deduplication_window_seconds_for_async_inserts) — устаревшие настройки. Синхронные и асинхронные вставки теперь используют один журнал дедупликации, поэтому `replicated_deduplication_window` управляет обеими. Устаревшие настройки ограничивали размер старого каталога ClickHouse Keeper, что важно при поэтапном обновлении.
</Note>

<div id="query-level-insert-deduplication">
  ### Настройки на уровне запроса
</div>

| Настройка                                                                                                                                                | Применяется к                                  | Значение по умолчанию  | Назначение                                                                 |
| -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ---------------------- | -------------------------------------------------------------------------- |
| [`deduplicate_insert`](/ru/reference/settings/session-settings/deduplicate-insert#deduplicate_insert)                                                    | Каждому `INSERT`, синхронному или асинхронному | `enable`               | Основной переключатель дедупликации вставок                                |
| [`deduplicate_insert_select`](/ru/reference/settings/session-settings/deduplicate-insert#deduplicate_insert_select)                                      | `INSERT ... SELECT`                            | `enable_when_possible` | Определяет, что делать, если результат `SELECT` невозможно воспроизвести   |
| [`insert_deduplication_token`](/ru/reference/settings/session-settings/insert#insert_deduplication_token)                                                | Каждому `INSERT`                               | `''`                   | Идентифицирует вставку по заданной пользователем строке, а не по данным    |
| [`deduplicate_blocks_in_dependent_materialized_views`](/ru/reference/settings/session-settings/other#deduplicate_blocks_in_dependent_materialized_views) | Таблицам, лежащим в основе materialized view   | `1`                    | Распространяет дедупликацию на целевые таблицы зависимых materialized view |

`deduplicate_insert` принимает три значения:

* `enable` — дедупликация включена для запроса `INSERT`.
* `disable` — дедупликация отключена для запроса `INSERT`.
* `backward_compatible_choice` — решение передаётся устаревшим настройкам `insert_deduplicate` (синхронные вставки) и `async_insert_deduplicate` (асинхронные вставки).

Обратите внимание: запрос, выполняемый с `deduplicate_insert = disable`, не записывает `block_id` для своих блоков. Такие данные нельзя дедуплицировать позднее, даже если повторить вставку с `deduplicate_insert = enable`. То же относится к случаям, когда целевая таблица не хранит журнал дедупликации: ничего не записывается, поэтому при повторной попытке сопоставить данные будет не с чем.

<div id="precedence">
  ### Старшинство
</div>

1. Для запроса `INSERT ... SELECT` определяющим является параметр `deduplicate_insert_select`. См. [Дедупликация для INSERT ... SELECT](#deduplication-for-insert-select).
2. Для всех остальных операций `INSERT` определяющим является параметр `deduplicate_insert`.
3. Параметры `insert_deduplicate` и `async_insert_deduplicate` учитываются только при значении `backward_compatible_choice` параметра `deduplicate_insert`.

<div id="legacy-and-obsolete-settings">
  ### Устаревшие и упразднённые настройки
</div>

| Настройка                                                                                                   | Статус                                                                               | Используйте вместо          |
| ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------- |
| [`insert_deduplicate`](/ru/reference/settings/session-settings/insert#insert_deduplicate)                   | Устаревшая. Считывается только при `deduplicate_insert = backward_compatible_choice` | `deduplicate_insert`        |
| [`async_insert_deduplicate`](/ru/reference/settings/session-settings/async-insert#async_insert_deduplicate) | Устаревшая. Считывается только при `deduplicate_insert = backward_compatible_choice` | `deduplicate_insert`        |
| `insert_select_deduplicate`                                                                                 | Упразднённая. Не влияет на работу                                                    | `deduplicate_insert_select` |
| `update_insert_deduplication_token_in_dependent_materialized_views`                                         | Упразднённая. Не влияет на работу                                                    | —                           |

<Warning>
  Начиная с версии 26.2, значением по умолчанию для `deduplicate_insert` является `enable`. Поэтому настройка `insert_deduplicate = 0` больше сама по себе не отключает дедупликацию. Чтобы отключить дедупликацию, установите `deduplicate_insert = disable`.
</Warning>

В версии 26.2 также были изменены значения по умолчанию для `async_insert` и `deduplicate_blocks_in_dependent_materialized_views`: теперь они включены. Настройка [`compatibility`](/ru/reference/settings/session-settings/compatibility#compatibility) управляет всеми тремя настройками. Если установить для `compatibility` версию ранее `26.2`, эти настройки сохранят прежние значения по умолчанию: для `deduplicate_insert` будет установлено `backward_compatible_choice`, и выбор будет передан `insert_deduplicate` и `async_insert_deduplicate`. Явно заданная настройка всегда применяется и не зависит от `compatibility`.

<div id="how-insert-deduplication-works">
  ## Как работает дедупликация при вставке
</div>

Когда данные вставляются в ClickHouse, система разбивает их на блоки в зависимости от количества строк и байтов.

Для таблиц, использующих движки `*MergeTree`, каждому блоку присваивается уникальный `block_id` — хеш данных в этом блоке. Этот `block_id` используется как уникальный ключ операции вставки. Если такой же `block_id` найден в журнале дедупликации, блок считается дубликатом и не вставляется в таблицу.

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

Для запросов `INSERT ... VALUES` разбиение вставляемых данных на блоки детерминировано и задаётся настройками. Поэтому повторные попытки вставки следует выполнять с теми же значениями настроек, что и в исходной операции.

<div id="deduplication-for-insert-select">
  ## Дедупликация для `INSERT ... SELECT`
</div>

Для запросов `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` (по умолчанию) | Выполнять дедупликацию, если `SELECT` стабилен или задан токен. В противном случае пропустить дедупликацию и записать сообщение в журнал сервера.                                                                           |
| `force_enable`                        | Всегда выполнять дедупликацию. Если `SELECT` нестабилен и токен не задан, сгенерировать исключение `DEDUPLICATION_IS_NOT_POSSIBLE`.                                                                                         |
| `enable_even_for_bad_queries`         | Выполнять дедупликацию независимо от стабильности. Сохранено для обратной совместимости. При нестабильном `SELECT` повторная попытка обычно не распознаётся как дубликат, поэтому предпочтительнее выбрать другое значение. |
| `disable`                             | Никогда не выполнять дедупликацию `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 не сможет дедуплицировать эти блоки.

<div id="deduplication-for-asynchronous-inserts">
  ## Дедупликация асинхронных вставок
</div>

Асинхронные вставки ([`async_insert`](/ru/reference/settings/session-settings/async-insert#async_insert), включенные по умолчанию с версии 26.2) дедуплицируются при повторных попытках так же, как синхронные вставки. Обоими типами управляет параметр `deduplicate_insert`, поэтому отдельный переключатель не нужен.

Оба типа вставок также используют общий журнал дедупликации и одинаково вычисляют `block_id`. Поэтому можно переключать клиент между синхронными и асинхронными вставками, не нарушая дедупликацию: повторная попытка, отправленная в одном режиме, всё равно будет распознана как дубликат попытки, отправленной в другом. Перевод рабочей нагрузки с синхронных на асинхронные вставки также безопасен для таблицы, использующей дедупликацию.

<Note>
  До версии 26.2 дедупликация асинхронных вставок по умолчанию была отключена и управлялась параметром `async_insert_deduplicate`. Теперь этот параметр учитывается только при значении `backward_compatible_choice` параметра `deduplicate_insert`.
</Note>

<div id="asynchronous-insert-deduplication-granularity">
  ### Гранулярность дедупликации
</div>

Сервер объединяет несколько асинхронных вставок в один батч и записывает его в виде одной или нескольких частей — как минимум по одной для каждого уникального значения ключа партиционирования. Дедупликация выполняется для каждого пользовательского запроса, а не для батча:

* Каждый запрос в очереди добавляет в батч один токен дедупликации.
* Токен — это либо значение `insert_deduplication_token`, если оно задано в запросе, либо хеш строк, добавленных этим запросом.
* Объединение в батчи не влияет на токены, а `insert_deduplication_token` не влияет на группировку запросов в батчи.

Это приводит к двум последствиям:

* Если один из запросов в батче является дубликатом, ClickHouse удаляет только строки этого запроса. Остальные данные из батча вставляются как обычно. Часть полностью пропускается только в том случае, если из неё удалены все строки.
* Если два запроса в одном батче имеют одинаковый токен, второй отбрасывается до записи части. Это применяется отдельно для каждой партиции: если два запроса записывают строки в разные партиции, оба сохраняются.

События `DuplicatedAsyncInserts` и `SelfDuplicatedAsyncInserts` в [`system.events`](/ru/reference/system-tables/events) учитывают эти два случая.

<div id="asynchronous-inserts-and-materialized-views">
  ### Асинхронные вставки и materialized view
</div>

Дедупликация асинхронных вставок работает совместно с зависимыми materialized view. Правило простое: один блок на входе — один блок на выходе. Если внутренний запрос представления преобразует один входной блок в один выходной, дедупликация работает. Если представление формирует второй блок, ClickHouse генерирует исключение `NOT_IMPLEMENTED`.

Представление формирует второй блок, когда его результат уже не помещается в один блок. [`max_block_size`](/ru/reference/settings/session-settings/max#max_block_size) задаёт количество строк, помещающихся в блок. Преобразования столбцов, фильтрация и агрегация никогда не добавляют строк, поэтому всегда остаются в одном блоке. `JOIN` может добавлять строки. Он работает, пока результат не превышает `max_block_size`, и завершается ошибкой при превышении этого значения.

Чтобы выполнять вставку через представление, формирующее более одного блока, либо установите `deduplicate_blocks_in_dependent_materialized_views = 0`, либо используйте синхронные вставки.

<div id="insert-deduplication-with-materialized-views">
  ## Дедупликация при вставке с materialized view
</div>

Если у таблицы есть одно или несколько materialized view, вставляемые данные также записываются в целевые таблицы этих представлений с заданными преобразованиями. Преобразованные данные тоже дедуплицируются при повторных попытках. ClickHouse выполняет дедупликацию для materialized view так же, как и для данных, вставляемых в целевую таблицу.

Управлять этим процессом можно с помощью следующих настроек исходной таблицы:

* [`replicated_deduplication_window`](/ru/reference/settings/merge-tree-settings/replicated-deduplication-window#replicated_deduplication_window)
* [`replicated_deduplication_window_seconds`](/ru/reference/settings/merge-tree-settings/replicated-deduplication-window#replicated_deduplication_window_seconds)
* [`non_replicated_deduplication_window`](/ru/reference/settings/merge-tree-settings/other#non_replicated_deduplication_window)

Дедупликация в таблицах materialized view дополнительно регулируется настройкой профиля пользователя [`deduplicate_blocks_in_dependent_materialized_views`](/ru/reference/settings/session-settings/other#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.

<div id="examples">
  ## Примеры
</div>

<div id="identical-blocks-after-materialized-view-transformations">
  ### Идентичные блоки после преобразований в materialized view
</div>

Идентичные блоки, сгенерированные при преобразовании внутри materialized view, не дедуплицируются, поскольку они основаны на разных вставленных данных.

Вот пример:

```sql theme={null}
CREATE TABLE dst
(
    `key` Int64,
    `value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;

CREATE MATERIALIZED VIEW mv_dst
(
    `key` Int64,
    `value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000
AS SELECT
    0 AS key,
    value AS value
FROM dst;
```

```sql theme={null}
SET max_block_size=1;
SET min_insert_block_size_rows=0;
SET min_insert_block_size_bytes=0;
```

Приведенные выше настройки позволяют выбирать данные из таблицы, состоящей из последовательности блоков, каждый из которых содержит только одну строку. Эти небольшие блоки не объединяются и остаются неизменными, пока не будут вставлены в таблицу.

Мы явно задаем дедупликацию в materialized view, хотя по умолчанию она включена:

```sql theme={null}
SET deduplicate_blocks_in_dependent_materialized_views=1;
```

```sql theme={null}
INSERT INTO dst SELECT
    number + 1 AS key,
    IF(key = 0, 'A', 'B') AS value
FROM numbers(2);

SELECT
    *,
    _part
FROM dst
ORDER BY all;
```

```response theme={null}
┌─key─┬─value─┬─_part─────┐
│   1 │ B     │ all_0_0_0 │
│   2 │ B     │ all_1_1_0 │
└─────┴───────┴───────────┘
```

Здесь мы видим, что в таблицу `dst` были вставлены две части. 2 блока из select -- 2 части при вставке. Эти части содержат разные данные.

```sql theme={null}
SELECT
    *,
    _part
FROM mv_dst
ORDER BY all;
```

```response theme={null}
┌─key─┬─value─┬─_part─────┐
│   0 │ B     │ all_0_0_0 │
│   0 │ B     │ all_1_1_0 │
└─────┴───────┴───────────┘
```

Здесь видно, что в таблицу `mv_dst` было вставлено 2 части. Эти части содержат одни и те же данные, однако дедупликация для них не выполнялась.

```sql theme={null}
INSERT INTO dst SELECT
    number + 1 AS key,
    IF(key = 0, 'A', 'B') AS value
FROM numbers(2);

SELECT
    *,
    _part
FROM dst
ORDER BY all;
```

```response theme={null}
┌─key─┬─value─┬─_part─────┐
│   1 │ B     │ all_0_0_0 │
│   2 │ B     │ all_1_1_0 │
└─────┴───────┴───────────┘
```

```sql theme={null}
SELECT
    *,
    _part
FROM mv_dst
ORDER by all;
```

```response theme={null}
┌─key─┬─value─┬─_part─────┐
│   0 │ B     │ all_0_0_0 │
│   0 │ B     │ all_1_1_0 │
└─────┴───────┴───────────┘
```

Здесь видно, что при повторной вставке все данные дедуплицируются. Дедупликация работает как для таблицы `dst`, так и для таблицы `mv_dst`.

<div id="identical-blocks-on-insertion">
  ### Идентичные блоки при вставке
</div>

```sql theme={null}
CREATE TABLE dst
(
    `key` Int64,
    `value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;

SET max_block_size=1;
SET min_insert_block_size_rows=0;
SET min_insert_block_size_bytes=0;
```

Вставка:

```sql theme={null}
INSERT INTO dst SELECT
    0 AS key,
    'A' AS value
FROM numbers(2);

SELECT
    'from dst',
    *,
    _part
FROM dst
ORDER BY all;
```

```response theme={null}
┌─'from dst'─┬─key─┬─value─┬─_part─────┐
│ from dst   │   0 │ A     │ all_0_0_0 │
└────────────┴─────┴───────┴───────────┘
```

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

<div id="identical-blocks-in-insertion-with-insert_deduplication_token">
  ### Идентичные блоки при вставке с `insert_deduplication_token`
</div>

```sql theme={null}
CREATE TABLE dst
(
    `key` Int64,
    `value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;

SET max_block_size=1;
SET min_insert_block_size_rows=0;
SET min_insert_block_size_bytes=0;
```

Вставка:

```sql theme={null}
INSERT INTO dst SELECT
    0 AS key,
    'A' AS value
FROM numbers(2)
SETTINGS insert_deduplication_token='some_user_token';

SELECT
    'from dst',
    *,
    _part
FROM dst
ORDER BY all;
```

```response theme={null}
┌─'from dst'─┬─key─┬─value─┬─_part─────┐
│ from dst   │   0 │ A     │ all_2_2_0 │
│ from dst   │   0 │ A     │ all_3_3_0 │
└────────────┴─────┴───────┴───────────┘
```

Как и ожидалось, были вставлены два идентичных блока.

```sql theme={null}
SELECT 'second attempt';

INSERT INTO dst SELECT
    0 AS key,
    'A' AS value
FROM numbers(2)
SETTINGS insert_deduplication_token='some_user_token';

SELECT
    'from dst',
    *,
    _part
FROM dst
ORDER BY all;
```

```response theme={null}
┌─'from dst'─┬─key─┬─value─┬─_part─────┐
│ from dst   │   0 │ A     │ all_2_2_0 │
│ from dst   │   0 │ A     │ all_3_3_0 │
└────────────┴─────┴───────┴───────────┘
```

При повторной вставке, как и ожидалось, выполняется дедупликация.

```sql theme={null}
SELECT 'third attempt';

INSERT INTO dst SELECT
    1 AS key,
    'b' AS value
FROM numbers(2)
SETTINGS insert_deduplication_token='some_user_token';

SELECT
    'from dst',
    *,
    _part
FROM dst
ORDER BY all;
```

```response theme={null}
┌─'from dst'─┬─key─┬─value─┬─_part─────┐
│ from dst   │   0 │ A     │ all_2_2_0 │
│ from dst   │   0 │ A     │ all_3_3_0 │
└────────────┴─────┴───────┴───────────┘
```

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

<div id="different-insert-operations-generate-the-same-data-after-transformation-in-the-underlying-table-of-the-materialized-view">
  ### Разные операции вставки после преобразования создают одинаковые данные в базовой таблице materialized view
</div>

```sql theme={null}
CREATE TABLE dst
(
    `key` Int64,
    `value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;

CREATE MATERIALIZED VIEW mv_dst
(
    `key` Int64,
    `value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000
AS SELECT
    0 AS key,
    value AS value
FROM dst;

SET deduplicate_blocks_in_dependent_materialized_views=1;

select 'first attempt';

INSERT INTO dst VALUES (1, 'A');

SELECT
    'from dst',
    *,
    _part
FROM dst
ORDER by all;
```

```response theme={null}
┌─'from dst'─┬─key─┬─value─┬─_part─────┐
│ from dst   │   1 │ A     │ all_0_0_0 │
└────────────┴─────┴───────┴───────────┘
```

```sql theme={null}
SELECT
    'from mv_dst',
    *,
    _part
FROM mv_dst
ORDER by all;
```

```response theme={null}
┌─'from mv_dst'─┬─key─┬─value─┬─_part─────┐
│ from mv_dst   │   0 │ A     │ all_0_0_0 │
└───────────────┴─────┴───────┴───────────┘
```

```sql theme={null}
select 'second attempt';

INSERT INTO dst VALUES (2, 'A');

SELECT
    'from dst',
    *,
    _part
FROM dst
ORDER by all;
```

```response theme={null}
┌─'from dst'─┬─key─┬─value─┬─_part─────┐
│ from dst   │   1 │ A     │ all_0_0_0 │
│ from dst   │   2 │ A     │ all_1_1_0 │
└────────────┴─────┴───────┴───────────┘
```

```sql theme={null}
SELECT
    'from mv_dst',
    *,
    _part
FROM mv_dst
ORDER by all;
```

```response theme={null}
┌─'from mv_dst'─┬─key─┬─value─┬─_part─────┐
│ from mv_dst   │   0 │ A     │ all_0_0_0 │
│ from mv_dst   │   0 │ A     │ all_1_1_0 │
└───────────────┴─────┴───────┴───────────┘
```

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

<div id="different-materialized-view-inserts-into-one-underlying-table-with-equivalent-data">
  ### Разные варианты вставки через materialized view в одну базовую таблицу с эквивалентными данными
</div>

```sql theme={null}
CREATE TABLE dst
(
    `key` Int64,
    `value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;

CREATE TABLE mv_dst
(
    `key` Int64,
    `value` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS non_replicated_deduplication_window=1000;

CREATE MATERIALIZED VIEW mv_first
TO mv_dst
AS SELECT
    0 AS key,
    value AS value
FROM dst;

CREATE MATERIALIZED VIEW mv_second
TO mv_dst
AS SELECT
    0 AS key,
    value AS value
FROM dst;

SET deduplicate_blocks_in_dependent_materialized_views=1;

select 'first attempt';

INSERT INTO dst VALUES (1, 'A');

SELECT
    'from dst',
    *,
    _part
FROM dst
ORDER by all;
```

```response theme={null}
┌─'from dst'─┬─key─┬─value─┬─_part─────┐
│ from dst   │   1 │ A     │ all_0_0_0 │
└────────────┴─────┴───────┴───────────┘
```

```sql theme={null}
SELECT
    'from mv_dst',
    *,
    _part
FROM mv_dst
ORDER by all;
```

```response theme={null}
┌─'from mv_dst'─┬─key─┬─value─┬─_part─────┐
│ from mv_dst   │   0 │ A     │ all_0_0_0 │
│ from mv_dst   │   0 │ A     │ all_1_1_0 │
└───────────────┴─────┴───────┴───────────┘
```

Два одинаковых блока были вставлены в таблицу `mv_dst` (как и ожидалось).

```sql theme={null}
SELECT 'second attempt';

INSERT INTO dst VALUES (1, 'A');

SELECT
    'from dst',
    *,
    _part
FROM dst
ORDER BY all;
```

```response theme={null}
┌─'from dst'─┬─key─┬─value─┬─_part─────┐
│ from dst   │   1 │ A     │ all_0_0_0 │
└────────────┴─────┴───────┴───────────┘
```

```sql theme={null}
SELECT
    'from mv_dst',
    *,
    _part
FROM mv_dst
ORDER by all;
```

```response theme={null}
┌─'from mv_dst'─┬─key─┬─value─┬─_part─────┐
│ from mv_dst   │   0 │ A     │ all_0_0_0 │
│ from mv_dst   │   0 │ A     │ all_1_1_0 │
└───────────────┴─────┴───────┴───────────┘
```

Для этой повторной попытки выполняется дедупликация в обеих таблицах: `dst` и `mv_dst`.
