Learning Platform
Глоссарий Troubleshooting
Урок 15.07 · 30 мин
Продвинутый
EXCHANGE TABLESRENAME TABLEAtomic database enginezero-downtime migrationhot-swap

Atomic DDL: EXCHANGE TABLES и zero-downtime миграции

Обновление схемы таблицы в production без даунтайма — одна из ключевых задач операционного управления ClickHouse. EXCHANGE TABLES обеспечивает атомарный swap двух таблиц: в один момент читатели видят старую версию, в следующий — новую, без переходного состояния. Это делает возможными zero-downtime миграции даже на таблицах с активными INSERT и SELECT.


EXCHANGE TABLES: атомарный swap

EXCHANGE TABLES a AND b — DDL-команда, которая атомарно меняет местами две таблицы. Читатели никогда не видят промежуточное состояние.

-- Создать новую версию таблицы с обновлённой схемой
CREATE TABLE events_v2 AS events;  -- Скопировать структуру

-- Наполнить новую таблицу данными
INSERT INTO events_v2 SELECT * FROM events;

-- Применить изменения схемы к новой таблице
ALTER TABLE events_v2 ADD COLUMN region LowCardinality(String) DEFAULT '';

-- Атомарный swap: в один момент events начинает указывать на новую версию
EXCHANGE TABLES events AND events_v2;

-- Теперь:
-- events — таблица с новой схемой (обновлённые данные)
-- events_v2 — старая таблица (для проверки и rollback)
DROP TABLE events_v2;  -- Очистить старую версию
TIP

Atomic database engine — default с ClickHouse 20.x. EXCHANGE TABLES работает без дополнительной настройки на всех актуальных версиях ClickHouse. Проверить тип engine базы данных: SELECT engine FROM system.databases WHERE name = 'default'.


RENAME TABLE: не атомично для нескольких объектов

RENAME TABLE выполняет переименование мгновенно для одного объекта, но не является атомичным при переименовании нескольких таблиц в одном операторе.

-- Одиночное RENAME: безопасно (атомично для 1 объекта)
RENAME TABLE events_old TO events_backup;

-- RENAME нескольких объектов: НЕ атомично
-- Между первым и вторым переименованием клиент может получить ошибку
RENAME TABLE events TO events_old, events_new TO events;  -- Опасно!
WARNING

RENAME TABLE — не атомично для нескольких объектов. Если выполнять RENAME TABLE a TO b, c TO a для горячей замены таблицы, между двумя операциями существует временное состояние, когда ни один из вариантов имени не работает корректно. Для безопасного hot-swap используйте EXCHANGE TABLES.

Сравнение: EXCHANGE vs RENAME

КритерийEXCHANGE TABLESRENAME TABLE
АтомарностьПолная (транзакционная)Только для одного объекта
Несколько объектовНе применимо (2 таблицы фиксированы)Не атомично
Читатели во время операцииВидят только старую или только новую версиюМогут получить ошибку “table not found”
Требует Atomic engineДа (default с 20.x)Нет
RollbackEXCHANGE TABLES events AND events_v2 сноваЕщё одно RENAME TABLE

Zero-downtime migration pattern

Полный паттерн замены таблицы с новой схемой без остановки сервиса:

-- Шаг 1: Создать новую таблицу с обновлённой схемой
CREATE TABLE events_v2 (
    event_time DateTime64(3)                           CODEC(Delta, ZSTD(1)),
    user_id    UInt64,
    action     LowCardinality(String),
    region     LowCardinality(String) DEFAULT '',       -- Новая колонка
    session_id String               DEFAULT ''          -- Ещё одна новая колонка
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/events_v2', '{replica}')
PARTITION BY toYYYYMM(event_time)
ORDER BY (user_id, event_time);

-- Шаг 2: Перелить исторические данные (параллельно с production-трафиком)
INSERT INTO events_v2
SELECT
    event_time,
    user_id,
    action,
    ''   AS region,      -- default для новой колонки
    ''   AS session_id   -- default для новой колонки
FROM events;

-- Шаг 3: Переключить production-трафик на новую таблицу
-- (применить новые ALTER к events_v2 если нужно)
ALTER TABLE events_v2 ADD COLUMN new_feature_flag UInt8 DEFAULT 0;

-- Шаг 4: Атомарный swap -- читатели не замечают переключения
EXCHANGE TABLES events AND events_v2;

-- Шаг 5: Очистить старую версию (теперь в events_v2 -- старые данные)
DROP TABLE events_v2;

Когда использовать EXCHANGE vs обычный ALTER

-- Предпочтительно ALTER когда:
-- - ADD/DROP COLUMN (metadata-only, instant)
-- - MODIFY COLUMN с совместимым типом
ALTER TABLE events ADD COLUMN extra_data String DEFAULT '';

-- Предпочтительно EXCHANGE TABLES когда:
-- - Полное переписывание схемы (ORDER BY меняется, типы несовместимы)
-- - Нужна гарантия rollback (старая таблица остаётся как events_v2)
-- - Данные нужно трансформировать при переносе (ETL + migrate)
-- - Смена движка таблицы (MergeTree -> ReplacingMergeTree)
EXCHANGE TABLES events AND events_v2;

Проверка завершения migration

-- Убедиться, что INSERT в events_v2 завершён
SELECT count() FROM events_v2;
-- Должно совпадать с events до swap

-- Проверить структуру после swap
SELECT name, type, default_expression
FROM system.columns
WHERE database = 'default' AND table = 'events'
ORDER BY position;

-- Проверить, что нет активных mutations на новой таблице
SELECT mutation_id, command, is_done
FROM system.mutations
WHERE database = 'default' AND table = 'events' AND is_done = 0;

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

  1. EXCHANGE TABLES a AND b — атомарный swap: Читатели никогда не видят промежуточное состояние. Требует Atomic database engine (default с ClickHouse 20.x).
  2. RENAME TABLE не атомично для нескольких объектов: При переименовании двух таблиц в одном операторе между операциями существует временное состояние с возможными ошибками “table not found”.
  3. Zero-downtime migration pattern: CREATE TABLE new -> INSERT INTO SELECT -> ALTER new -> EXCHANGE -> DROP old. Читатели продолжают работать с production-трафиком на всех шагах.
  4. Rollback через повторный EXCHANGE: До DROP TABLE old всегда можно вернуться к предыдущей версии одной командой EXCHANGE TABLES events AND events_v2.
Снапшоты транзакций в PostgreSQL: snapshot isolation и DDL ELT паттерны: staging tables, transformations и production swap

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

Результат: 0 из 0
Прикладной
Вопрос 1 из 3. Необходимо выполнить hot-swap production-таблицы `events` на новую версию `events_v2` (с обновлённой схемой и свежими данными) без даунтайма. Пользователи непрерывно выполняют SELECT к `events`. Какая команда обеспечивает атомарный переключатель?

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

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

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

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