Поддержка транзакций (ACID)
Случай 1: INSERT в одну партицию одной таблицы семейства MergeTree*
Это транзакционно (ACID), если вставленные строки упаковываются и вставляются как единый блок (см. Заметки):
- Атомарность: команда INSERT выполняется успешно или отклоняется целиком: если подтверждение отправлено клиенту, то все строки были вставлены; если ошибка отправлена клиенту, то ни одна строка не была вставлена.
- Согласованность: если не нарушены ограничения таблицы, то все строки в INSERT вставлены и команда INSERT завершена успешно; если ограничения нарушены, то ни одна строка не вставлена.
- Изолированность: параллельные клиенты наблюдают последовательный снимок таблицы - состояние таблицы либо до попытки INSERT, либо после успешного INSERT; никакое частичное состояние не видно. Клиенты внутри другой транзакции имеют изоляцию снимка, в то время как клиенты вне транзакции находятся на уровне изоляции чтения неподтверждённых данных.
- Долговечность: успешный INSERT записывается в файловую систему до ответа клиенту, на одной реплике или нескольких репликах (контролируется настройкой
insert_quorum
), и ClickHouse может попросить операционную систему синхронизировать данные файловой системы на носителе (контролируется настройкойfsync_after_insert
). - INSERT в несколько таблиц с одной командой возможен, если участвуют материализованные представления (INSERT от клиента идет в таблицу, которая имеет связанные материализованные представления).
Случай 2: INSERT в несколько партиций одной таблицы семейства MergeTree*
То же самое, что и в Случае 1, с этой деталью:
- Если таблица имеет много партиций, и INSERT охватывает много партиций, то вставка в каждую партицию транзакционна сама по себе.
Случай 3: INSERT в одну распределённую таблицу семейства MergeTree*
То же самое, что и в Случае 1, с этой деталью:
- INSERT в распределённую таблицу не является транзакционным в целом, хотя вставка в каждую шарду является транзакционной.
Случай 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 МБ по умолчанию), если используется параллельный разбор (включен по умолчанию). - формат вставки основан на колонках (например, Native, Parquet, ORC и т.д.) и данные содержат только один блок данных.
- формат вставки основан на строках (например, CSV, TSV, Values, JSONEachRow и т.д.) и данные содержат меньше чем
- Размер вставленного блока в общем может зависеть от многих настроек (например:
max_block_size
,max_insert_block_size
,min_insert_block_size_rows
,min_insert_block_size_bytes
,preferred_block_size_bytes
и т.д.). - Если клиент не получил ответа от сервера, он не знает, удалось ли выполнение транзакции, и может повторить транзакцию, используя свойства вставки "точно один раз".
- ClickHouse использует MVCC с изоляцией снимка внутри для параллельных транзакций.
- Все свойства ACID действительны даже в случае отключения/сбоя сервера.
- Либо insert_quorum в разных AZ, либо fsync должны быть включены для обеспечения долговечных вставок в типичной настройке.
- "Согласованность" в терминах ACID не охватывает семантику распределённых систем, см. https://jepsen.io/consistency, над которой контролируются разные настройки (select_sequential_consistency).
- Это объяснение не охватывает новую функциональность транзакций, позволяющую иметь полнофункциональные транзакции на нескольких таблицах, материализованных представлениях, для нескольких SELECT и т.д. (см. следующий раздел о Транзакциях, Коммитах и Откатах).
Транзакции, Коммиты и Откаты
В дополнение к функциональности, описанной в начале этого документа, ClickHouse имеет экспериментальную поддержку транзакций, коммитов и функциональности откатов.
Требования
- Разверните ClickHouse Keeper или ZooKeeper для отслеживания транзакций.
- Только атомарные базы данных (по умолчанию).
- Только движок таблиц Non-Replicated MergeTree.
- Включите экспериментальную поддержку транзакций, добавив эту настройку в
config.d/transactions.xml
:
Заметки
- Это экспериментальная функция, и ожидаются изменения.
- Если происходит исключение в процессе транзакции, вы не можете выполнить коммит транзакции. Это включает все исключения, в том числе исключения
UNKNOWN_FUNCTION
, вызванные опечатками. - Вложенные транзакции не поддерживаются; завершите текущую транзакцию и начните новую.
Конфигурация
Эти примеры для одноузлового сервера ClickHouse с включённым ClickHouse Keeper.
Включите экспериментальную поддержку транзакций
Основная конфигурация для одноузлового сервера ClickHouse с включённым ClickHouse Keeper
Смотрите документацию по развёртыванию для получения подробностей о развертывании сервера ClickHouse и правильном кворуме узлов ClickHouse Keeper. Показанная здесь конфигурация предназначена для экспериментальных целей.
Пример
Проверьте, что экспериментальные транзакции включены
Выдайте BEGIN TRANSACTION
или START TRANSACTION
, затем ROLLBACK
, чтобы проверить, что экспериментальные транзакции включены и что ClickHouse Keeper включён, так как он используется для отслеживания транзакций.
Если вы видите следующую ошибку, то проверьте ваш конфигурационный файл, чтобы убедиться, что allow_experimental_transactions
установлен в 1
(или любое значение, кроме 0
или false
).
Вы также можете проверить ClickHouse Keeper, выдав
ClickHouse Keeper должен ответить imok
.
Создайте таблицу для тестирования
Создание таблиц не является транзакционным. Выполните этот DDL-запрос вне транзакции.
Начните транзакцию и вставьте строку
Вы можете запрашивать таблицу изнутри транзакции и увидеть, что строка была вставлена, даже если она ещё не была зафиксирована.
Откатите транзакцию и снова запросите таблицу
Проверьте, что транзакция откатилась:
Завершите транзакцию и снова запросите таблицу
Инспекция транзакций
Вы можете просматривать транзакции, выполняя запрос к таблице system.transactions
, но имейте в виду, что вы не можете запрашивать эту таблицу из сессии, находящейся в транзакции. Откройте вторую сессию clickhouse client
, чтобы выполнить запрос к этой таблице.
Дополнительные детали
Смотрите этот мета-вопрос, чтобы увидеть гораздо более обширные тесты и быть в курсе прогресса.