Перейти к основному содержанию

Случай 1: INSERT в одну партицию одной таблицы семейства MergeTree*

Это транзакционная операция (ACID), если вставляемые строки упакованы и вставляются как один блок (см. примечания):
  • Атомарность: INSERT либо выполняется целиком, либо целиком отклоняется: если клиенту отправлено подтверждение, значит, были вставлены все строки; если клиенту отправлена ошибка, значит, не была вставлена ни одна строка.
  • Согласованность: если ограничения таблицы не нарушены, то все строки из INSERT вставляются и INSERT завершается успешно; если ограничения нарушены, то не вставляется ни одна строка.
  • Изоляция: параллельные клиенты видят согласованный снимок таблицы — состояние таблицы либо до попытки INSERT, либо после успешного INSERT; никакое частичное состояние не наблюдается. Клиенты внутри другой транзакции имеют изоляцию снимков, тогда как клиенты вне транзакции имеют уровень изоляции read uncommitted.
  • Надёжность: успешный INSERT записывается в файловую систему до отправки ответа клиенту, на одной реплике или нескольких репликах (управляется настройкой insert_quorum), и ClickHouse может потребовать от ОС синхронизировать данные файловой системы с носителем данных (управляется настройкой fsync_after_insert).
  • INSERT в несколько таблиц одним оператором возможен, если задействованы materialized view (INSERT со стороны клиента выполняется в таблицу, с которой связаны materialized view).

Случай 2: INSERT в несколько партиций одной таблицы семейства MergeTree*

То же, что и в случае 1 выше, со следующей особенностью:
  • Если у таблицы много партиций и INSERT охватывает много партиций, то вставка в каждую партицию выполняется как отдельная транзакция

Случай 3: INSERT в одну distributed таблицу семейства MergeTree*

То же, что и в случае 1 выше, но с одной оговоркой:
  • INSERT в таблицу Distributed в целом не является транзакционным, тогда как вставка в каждый сегмент транзакционна

Случай 4: Использование таблицы Buffer

  • вставка в таблицы Buffer не обладает ни атомарностью, ни изолированностью, ни согласованностью, ни долговечностью

Случай 5: Использование async_insert

То же, что и в случае 1 выше, со следующим уточнением:
  • атомарность обеспечивается, даже если async_insert включен и для wait_for_async_insert установлено значение 1 (по умолчанию), но если для wait_for_async_insert установлено значение 0, то атомарность не гарантируется.

Примечания

  • строки, вставляемые клиентом в некотором формате данных, упаковываются в один блок, если:
    • формат вставки является построчным (например, CSV, TSV, Values, JSONEachRow и т. д.), а данные содержат менее max_insert_block_size строк (~1 000 000 по умолчанию) или менее min_chunk_bytes_for_parallel_parsing байт (10 MB по умолчанию), если используется параллельный парсинг (он включен по умолчанию)
    • формат вставки является постолбцовым (например, Native, Parquet, ORC и т. д.), а данные содержат только один блок данных
  • размер вставленного блока в общем случае может зависеть от многих настроек (например: max_block_size, max_insert_block_size, min_insert_block_size_rows, min_insert_block_size_bytes, preferred_block_size_bytes и т. д.)
  • если клиент не получил ответ от сервера, он не знает, завершилась ли транзакция успешно, и может повторить транзакцию, используя свойства exactly-once для вставки
  • ClickHouse внутренне использует MVCC с изоляцией снимков для параллельных транзакций
  • все свойства ACID сохраняются даже в случае принудительного завершения работы или сбоя сервера
  • для обеспечения надежности вставки в типичной конфигурации должен быть включен либо insert_quorum между разными AZ, либо fsync
  • «consistency» в терминах ACID не охватывает семантику распределенных систем, см. https://jepsen.io/consistency; она регулируется другими настройками (select_sequential_consistency)
  • это объяснение не охватывает новую возможность транзакций, которая позволяет использовать полнофункциональные транзакции для нескольких таблиц, materialized view, нескольких SELECT и т. д. (см. следующий раздел о Transactions, Commit, and Rollback)

Транзакции, фиксация и откат

Помимо функциональности, описанной в начале этого документа, ClickHouse экспериментально поддерживает транзакции, фиксацию и откат.

Требования

  • Разверните ClickHouse Keeper или ZooKeeper для отслеживания транзакций
  • Только БД с движком Atomic (по умолчанию)
  • Только движок таблицы MergeTree без репликации
  • Включите экспериментальную поддержку транзакций, добавив этот параметр в config.d/transactions.xml:
    <clickhouse>
      <allow_experimental_transactions>1</allow_experimental_transactions>
    </clickhouse>
    

Примечания

  • Это экспериментальная возможность, и в ней возможны изменения.
  • Если во время транзакции возникает исключение, зафиксировать транзакцию нельзя. Это относится ко всем исключениям, включая исключения UNKNOWN_FUNCTION, вызванные опечатками.
  • Вложенные транзакции не поддерживаются; вместо этого завершите текущую транзакцию и начните новую

Конфигурация

В этих примерах используется одноузловой сервер ClickHouse с включенным ClickHouse Keeper.

Включите экспериментальную поддержку транзакций

/etc/clickhouse-server/config.d/transactions.xml
<clickhouse>
    <allow_experimental_transactions>1</allow_experimental_transactions>
</clickhouse>

Базовая конфигурация для одного узла сервера ClickHouse с включенным ClickHouse Keeper

Подробные сведения о развертывании сервера ClickHouse и корректном кворуме узлов ClickHouse Keeper см. в документации по развертыванию. Показанная здесь конфигурация предназначена для экспериментальных целей.
/etc/clickhouse-server/config.d/config.xml
<clickhouse replace="true">
    <logger>
        <level>debug</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <display_name>node 1</display_name>
    <listen_host>0.0.0.0</listen_host>
    <http_port>8123</http_port>
    <tcp_port>9000</tcp_port>
    <zookeeper>
        <node>
            <host>clickhouse-01</host>
            <port>9181</port>
        </node>
    </zookeeper>
    <keeper_server>
        <tcp_port>9181</tcp_port>
        <server_id>1</server_id>
        <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
        <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
        <coordination_settings>
            <operation_timeout_ms>10000</operation_timeout_ms>
            <session_timeout_ms>30000</session_timeout_ms>
            <raft_logs_level>information</raft_logs_level>
        </coordination_settings>
        <raft_configuration>
            <server>
                <id>1</id>
                <hostname>clickhouse-keeper-01</hostname>
                <port>9234</port>
            </server>
        </raft_configuration>
    </keeper_server>
</clickhouse>

Пример

Убедитесь, что экспериментальные транзакции включены

Выполните BEGIN TRANSACTION или START TRANSACTION, а затем ROLLBACK, чтобы убедиться, что экспериментальные транзакции включены и что ClickHouse Keeper тоже включен, поскольку он используется для отслеживания транзакций.
BEGIN TRANSACTION
Ok.
Если вы видите следующую ошибку, проверьте файл конфигурации и убедитесь, что параметр allow_experimental_transactions имеет значение 1 (или любое значение, кроме 0 или false).
Code: 48. DB::Exception: Received from localhost:9000.
DB::Exception: Transactions are not supported.
(NOT_IMPLEMENTED)
Вы также можете проверить ClickHouse Keeper, выполнив команду:
echo ruok | nc localhost 9181
ClickHouse Keeper должен ответить imok.
ROLLBACK
Ok.

Создайте таблицу для тестирования

Создание таблиц не поддерживает транзакции. Выполните этот DDL-запрос вне транзакции.
CREATE TABLE mergetree_table
(
    `n` Int64
)
ENGINE = MergeTree
ORDER BY n
Ok.

Начните транзакцию и вставьте строку

BEGIN TRANSACTION
Ok.
INSERT INTO mergetree_table FORMAT Values (10)
Ok.
SELECT *
FROM mergetree_table
┌──n─┐
│ 10 │
└────┘
Вы можете выполнить запрос к таблице в рамках транзакции и увидеть, что строка уже вставлена, хотя транзакция еще не зафиксирована.

Откатите транзакцию и снова выполните запрос к таблице

Убедитесь, что откат транзакции выполнен:
ROLLBACK
Ok.
SELECT *
FROM mergetree_table
Ok.

0 rows in set. Elapsed: 0.002 sec.

Завершите транзакцию и повторно выполните запрос к таблице

BEGIN TRANSACTION
Ok.
INSERT INTO mergetree_table FORMAT Values (42)
Ok.
COMMIT
Ok. Elapsed: 0.002 sec.
SELECT *
FROM mergetree_table
┌──n─┐
│ 42 │
└────┘

Просмотр транзакций

Проверить транзакции можно, выполнив запрос к таблице system.transactions, но учтите, что эту таблицу нельзя запрашивать из сеанса, в котором открыта транзакция. Откройте второй сеанс клиент ClickHouse, чтобы выполнить запрос к этой таблице.
SELECT *
FROM system.transactions
FORMAT Vertical
Row 1:
──────
tid:         (33,61,'51e60bce-6b82-4732-9e1d-b40705ae9ab8')
tid_hash:    11240433987908122467
elapsed:     210.017820947
is_readonly: 1
state:       RUNNING

Более подробная информация

См. эту мета-задачу, чтобы ознакомиться с гораздо более обширными тестами и следить за ходом работ.
Последнее изменение 10 июня 2026 г.