Apache Iceberg. Упражнение: Эволюция схемы

Практика эволюции схемы

|

Пора применить теорию на практике. В этом упражнении вы создадите таблицу Iceberg, последовательно измените её схему и убедитесь, что все операции безопасны и обратимы.

Цели

  • Создать таблицу user_events с базовой схемой.
  • Добавить новые колонки без перезаписи данных.
  • Удалить колонку и проверить, что данные остаются доступны через time travel.
  • Переименовать колонку и убедиться, что исторические запросы работают.
  • Расширить тип колонки (widening).
  • Изменить порядок колонок для улучшения читаемости.

Предварительные требования

  • Локальное окружение Iceberg (как в упражнении «Каталоги»).
  • Доступ к Spark SQL или другому движку, поддерживающему Iceberg.
  • Около 20 минут.

Шаг 1: Запуск окружения

Если у вас ещё не запущено локальное окружение, выполните команды из упражнения «Каталоги»:

cd iceberg-course-exercisesdocker compose up -d

Подключитесь к Spark SQL:

docker compose exec -it spark-iceberg spark-sql --conf "spark.hadoop.hive.cli.print.header=true"

Убедитесь, что каталог demo доступен:

SHOW CATALOGS;

Создайте базу данных для упражнения:

CREATE NAMESPACE demo.schema_evolution;USE demo.schema_evolution;

Шаг 2: Создание исходной таблицы

Создадим таблицу user_events с тремя колонками:

CREATE TABLE user_events (    event_id BIGINT,    user_id INT,    event_type STRING)USING icebergTBLPROPERTIES ('format-version'='2');

Вставим несколько тестовых записей:

INSERT INTO user_events VALUES    (1, 1001, 'login'),    (2, 1002, 'purchase'),    (3, 1001, 'logout');

Проверим, что данные записались:

SELECT * FROM user_events ORDER BY event_id;
event_id user_id event_type
1 1001 login
2 1002 purchase
3 1001 logout

Шаг 3: Добавление колонок

Маркетинг просит добавить информацию об устройстве и версии браузера. Выполним:

ALTER TABLE user_events ADD COLUMNS (    device_type STRING,    browser_version STRING);

Теперь вставим новую запись с заполненными новыми колонками:

INSERT INTO user_events VALUES    (4, 1003, 'view', 'mobile', 'Chrome 120');

Запросим таблицу:

SELECT * FROM user_events ORDER BY event_id;
event_id user_id event_type device_type browser_version
1 1001 login NULL NULL
2 1002 purchase NULL NULL
3 1001 logout NULL NULL
4 1003 view mobile Chrome 120

Вы видите, что старые записи имеют NULL в новых колонках, а новая запись — заполненные значения. Это обычное поведение реляционных баз, но в Iceberg оно достигнуто без перезаписи файлов.

Шаг 4: Удаление колонки

Через некоторое время выясняется, что browser_version больше не нужна. Удалим её:

ALTER TABLE user_events DROP COLUMN browser_version;

Запросим таблицу — колонка исчезла:

SELECT * FROM user_events ORDER BY event_id;
event_id user_id event_type device_type
1 1001 login NULL
2 1002 purchase NULL
3 1001 logout NULL
4 1003 view mobile

Куда делись данные? Они остались в хранилище, но скрыты от текущего снапшота. Давайте проверим с помощью time travel.

Шаг 5: Time travel к предыдущему снапшоту

Узнаем ID снапшота перед удалением колонки. Сначала посмотрим историю снапшотов:

SELECT    snapshot_id,    committed_at,    operationFROM demo.schema_evolution.user_events.snapshotsORDER BY committed_at;

Запомните snapshot_id того снапшота, где колонка ещё существовала (скорее всего, второй сверху). Используем его в запросе:

snapshot_id committed_at operation
6360110623641157946 2026-05-17 15:59:41.026 append
4736823070948074103 2026-05-17 16:00:08.225 append
SELECT *FROM demo.schema_evolution.user_eventsFOR VERSION AS OF <snapshot_id>ORDER BY event_id;

Вы снова увидите колонку browser_version! Это доказывает, что Iceberg не стирает данные при удалении колонки — он лишь помечает её как удалённую в метаданных.

Шаг 6: Переименование колонки

Колонка event_type кажется недостаточно описательной. Переименуем её в action_category:

ALTER TABLE user_events RENAME COLUMN event_type TO action_category;

Проверим, что переименование сработало:

SELECT action_category, user_id FROM user_events ORDER BY event_id;
action_category user_id
login 1001
purchase 1002
logout 1001
view 1003

Исторические данные остались доступны — они просто теперь фигурируют под новым именем. Если вы выполните time travel к снапшоту до переименования, там колонка будет называться event_type.

Шаг 7: Расширение типа колонки (widening)

Предположим, у вас внезапно появилось более 4,2 миллиарда пользователей (поздравляем!). Колонка user_id типа INT уже не вмещает такие значения. Расширим её до BIGINT:

ALTER TABLE user_events ALTER COLUMN user_id TYPE BIGINT;

Вставьте запись с большим значением user_id:

INSERT INTO user_events VALUES (5, 5000000000, 'click', 'desktop');

Запросите таблицу — всё работает. Старые данные по‑прежнему хранятся как INT, но при чтении автоматически приводятся к BIGINT.

Шаг 8: Изменение порядка колонок

Таблица стала выглядеть неупорядоченно. Давайте переместим action_category сразу после event_id для лучшей читаемости:

ALTER TABLE user_events ALTER COLUMN action_category AFTER event_id;

Проверим схему:

DESCRIBE user_events;
col_name data_type comment
event_id bigint
action_category string
user_id bigint
device_type string

Колонки теперь идут в порядке: event_id, action_category, user_id, device_type. Ни один файл данных не был перезаписан — только метаданные.

Шаг 9: Эволюция комплексного типа (опционально)

Если ваш движок поддерживает, можно попробовать работу со структурами. Создадим новую таблицу с полем‑структурой:

CREATE TABLE user_prefs (    user_id BIGINT,    preferences STRUCT<email_notifications:BOOLEAN, color_theme:STRING>)USING iceberg;

Добавим поле в структуру:

ALTER TABLE user_prefs ADD COLUMN preferences.mobile_notifications BOOLEAN;
col_name data_type comment
user_id bigint
preferences struct<email_notifications:boolean,color_theme:string,mobile_notifications:boolean>

Это демонстрирует, что эволюция схемы работает и для вложенных типов.

Что вы узнали

  • Добавление колонок — мгновенная операция, старые записи получают NULL.
  • Удаление колонок — данные не стираются, остаются доступны через time travel.
  • Переименование колонок — меняется только имя в метаданных, исторические запросы работают.
  • Расширение типов — безопасное приведение при чтении без перезаписи.
  • Изменение порядка колонок — чисто косметическое изменение, не затрагивающее данные.
  • Time travel — мощный инструмент для доступа к предыдущим состояниям схемы и данных.

Эволюция — это не революция. Iceberg позволяет менять схему постепенно, без катастрофических последствий. Как садовник, который подрезает ветви, а не вырубает дерево.


Что дальше? В следующем уроке мы изучим Партицирование и эволюция партиций — как организовать данные для эффективных запросов и менять стратегию партицирования без перезаписи.

→ Вперёд к партицированию

← Назад к типам данных и эволюции схемы