Apache Iceberg. Метатаблицы

Рентген для данных

|

Метатаблицы Iceberg — это как рентген для ваших данных: можно заглянуть внутрь, не вскрывая пациента. Только не удивляйтесь, если обнаружите, что некоторые файлы ведут себя странно — это нормально для данных, которые живут своей жизнью.

Что такое метатаблицы и зачем они нужны

Метатаблицы Iceberg — это системные таблицы, которые дают вам доступ к внутреннему состоянию таблицы Iceberg через обычный SQL. Вместо того чтобы копаться в JSON-файлах метаданных или писать сложные скрипты, вы можете просто выполнить SELECT и увидеть, что происходит внутри таблицы.

-- Обычная таблицаSELECT * FROM sales; -- Метаданные таблицыSELECT * FROM sales.history;                              -- история измененийSELECT * FROM sales.snapshots;                        -- информация о снэпшотахSELECT * FROM sales.files;                                   -- файлы с даннымиSELECT * FROM sales.manifests;                         -- файлы манифестовSELECT * FROM sales.partitions;                         -- статистика партицийSELECT * FROM sales.refs;                                   -- ветки и тегиSELECT * FROM sales.entries;                              -- изменения свойствSELECT * FROM sales.metadata_log_entries;   -- изменения свойств

Зачем это нужно?

  • Отладка производительности — понять, почему запросы стали медленнее
  • Анализ файлов — увидеть распределение файлов по партициям, их размеры, количество
  • Мониторинг здоровья — отслеживать рост таблицы, количество снапшотов, состояние манифестов
  • Планирование обслуживания — определить, какие партиции нуждаются в компактификации

Метатаблицы доступны через синтаксис table_name.metadata_table_name. Например, если ваша таблица называется orders, то метатаблица снапшотов будет orders.snapshots. Рассмотрим на примере из прошлого упражнения.

`snapshots` — снапшоты таблицы

Показывает все снапшоты таблицы: их ID, родительские снапшоты, временные метки и путь к файлу манифест-листа.

SELECT *FROM finance.transactions.snapshotsORDER BY committed_at DESCLIMIT 1;
Поле Значение
committed_at 2026-06-14 11:18:40.953
snapshot_id 3007366648374978862
parent_id 1739356557666905284
operation overwrite
manifest_list s3://warehouse/finance/transactions/metadata/snap-3007366648374978862-1-4e1273c4-19a3-40f2-ab58-212bb6e8401b.avro
summary {
    "added-data-files": "1",
    "added-files-size": "2196",
    "added-records": "4",
    "app-id": "local-1781435738405",
    "changed-partition-count": "1",
    "deleted-data-files": "4",
    "deleted-records": "4",
    "engine-name": "spark",
    "engine-version": "3.5.5",
    "iceberg‑version": "Apache Iceberg 1.8.1 (commit 9ce0fcf0af7becf25ad9fc996c3bad2afdcfd33d)",
    "removed-files-size": "8260",
    "spark.app.id": "local-1781435738405",
    "total-data-files": "9",
    "total-delete-files": "0",
    "total-equality-deletes": "0",
    "total-files-size": "18539",
    "total-position-deletes": "0",
    "total-records": "12"
}

Типичные случаи использования:

  • Просмотр истории изменений таблицы
  • Понимание, какие операции (append, replace, delete) происходили
  • Поиск конкретного снапшота для time travel

`manifests` — манифесты

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

SELECT *FROM finance.transactions.manifestsLIMIT 1;
Поле Значение
content 0
path s3://warehouse/finance/transactions/metadata/4e1273c4-19a3-40f2-ab58-212bb6e8401b-m1.avro
length 7418
partition_spec_id 0
added_snapshot_id 3007366648374978862
added_data_files_count 1
existing_data_files_count 0
deleted_data_files_count 0
added_delete_files_count 0
existing_delete_files_count 0
deleted_delete_files_count 0
partition_summaries []

Типичные случаи использования:

  • Понимание распределения данных по манифестам
  • Выявление манифестов с большим количеством мелких файлов
  • Отслеживание эффективности компактификации

`files` — файлы данных

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

SELECT *FROM finance.transactions.filesLIMIT 1;
Поле Значение
content 0
file_path s3://warehouse/finance/transactions/data/00000-17-c6bbfe6a-aba4-4aac-8968-54cedc04f16c-0-00001.parquet
file_format PARQUET
spec_id 0
record_count 4
file_size_in_bytes 2196
column_sizes {1:64,2:95,3:57,4:68,5:163,6:42}
value_counts {1:4,2:4,3:4,4:4,5:4,6:4}
null_value_counts {1:0,2:0,3:0,4:0,5:0,6:0}
nan_value_counts {}
lower_bounds {1:�,2:d,3:�N,4:�,5:Депозит нового к,6:}
upper_bounds {1:�,2:g,3:�N,4:�`,5:Получен возврат,6:}
key_metadata NULL
split_offsets [4]
equality_ids NULL
sort_order_id 0
referenced_data_file NULL
content_offset NULL
content_size_in_bytes NULL
readable_metrics {
    "account_id": {
        "column_size":95,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":100,
        "upper_bound":103
    },
    "amount": {
        "column_size":68,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":-750.00,
        "upper_bound":15000.00
    },
    "description": {
        "column_size":163,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":"Депозит нового к",
        "upper_bound":"Получен возврат"
    },
    "transaction_date": {
        "column_size":57,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":2025-02-10,
        "upper_bound":2025-02-12
    },
    "transaction_id": {
        "column_size":64,
        "value_count":4,
        "null_value_count":0,"nan_value_count":null,
        "lower_bound":1009,
        "upper_bound":1012
    },
    "verified": {
        "column_size":42,
        "value_count":4,
        "null_value_count":0,"nan_value_count":null,
        "lower_bound":true,
        "upper_bound":true
    }
}

Типичные случаи использования:

  • Анализ распределения размеров файлов
  • Поиск слишком маленьких или слишком больших файлов
  • Понимание, какие партиции содержат больше всего данных
  • Отладка проблем с партицированием

`partitions` — партиции

Показывает информацию о партициях таблицы: их спецификацию, количество файлов, записей, размер.

SELECT *FROM finance.transactions.partitionsLIMIT 1;
Поле Значение
record_count 12
file_count 9
total_data_file_size_in_bytes 18539
position_delete_record_count 0
position_delete_file_count 0
equality_delete_record_count 0
equality_delete_file_count 0
last_updated_at 2026-06-14 11:18:40.953
last_updated_snapshot_id 3007366648374978862

Типичные случаи использования:

  • Мониторинг роста партиций
  • Выявление несбалансированных партиций
  • Планирование обслуживания

`refs` — ссылки (ветки и теги)

Показывает все ветки и теги таблицы, их тип, связанный снапшот и максимальный возраст ссылки.

SELECT *FROM finance.transactions.refsLIMIT 1;
Поле Значение
name feb-2025-close
type TAG
snapshot_id 3007366648374978862
max_reference_age_in_ms NULL
min_snapshots_to_keep NULL
max_snapshot_age_in_ms NULL

Типичные случаи использования:

  • Просмотр всех веток и тегов таблицы
  • Понимание, какие снапшоты защищены от удаления
  • Отладка политик удержания

`entries` — записи манифеста

Предоставляет детальную информацию на уровне отдельных записей в манифестах: статус (добавлен/удалён), данные файла, последовательный номер, номер снапшота.

SELECT *FROM finance.transactions.entriesLIMIT 1;
Поле Значение
status 1
snapshot_id 3007366648374978862
sequence_number 4
file_sequence_number 4
data_file {
    "content":0,
    "file_path":"s3://warehouse/finance/transactions/data/00000-17-c6bbfe6a-aba4-4aac-8968-54cedc04f16c-0-00001.parquet",
    "file_format":"PARQUET",
    "spec_id":0,
    "record_count":4,
    "file_size_in_bytes":2196,
    "column_sizes": {
        1:64,
        2:95,
        3:57,
        4:68,
        5:163,
        6:42
    },
    "value_counts": {
        1:4,
        2:4,
        3:4,
        4:4,
        5:4,
        6:4
    },
    "null_value_counts": {
        1:0,
        2:0,
        3:0,
        4:0,
        5:0,
        6:0
    },
    "nan_value_counts": { },
    "lower_bounds": {
        1:�,
        2:d,
        3:�N,
        4:�,
        5:Депозит нового к,
        6:
    },
    "upper_bounds": {
        1:�,
        2:g,
        3:�N,
        4:�`,
        5:Получен возврат,
        6:
    },
    "key_metadata":null,
    "split_offsets":[4],
    "equality_ids":null,
    "sort_order_id":0,
    "referenced_data_file":null,
    "content_offset":null,
    "content_size_in_bytes":null
}
readable_metrics {
    "account_id": {
        "column_size":95,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":100,
        "upper_bound":103
    },
    "amount": {
        "column_size":68,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":-750.00,
        "upper_bound":15000.00
    },
    "description": {
        "column_size":163,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":"Депозит нового к",
        "upper_bound":"Получен возврат"
    },
    "transaction_date": {
        "column_size":57,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":2025-02-10,
        "upper_bound":2025-02-12
    },
    "transaction_id": {
        "column_size":64,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":1009,
        "upper_bound":1012
    },
    "verified": {
        "column_size":42,
        "value_count":4,
        "null_value_count":0,
        "nan_value_count":null,
        "lower_bound":true,
        "upper_bound":true
    }
}

Типичные случаи использования:

  • Детальный аудит изменений
  • Понимание, какие файлы были добавлены или удалены в конкретном снапшоте
  • Отладка проблем с дублированием данных

Практические примеры

Мониторинг роста таблицы

-- Почему моя таблица внезапно вырослаWITH daily_growth AS (  SELECT    DATE(committed_at) as date,    SUM(CAST(summary['added-files-size'] AS BIGINT))/1024/1024/1024 as gb_added  FROM sales.snapshots  WHERE committed_at > current_date - 7  GROUP BY 1)SELECT * FROM daily_growthWHERE gb_added > 100;
date gb_added
2025-11-27 342.7
2025-11-28 387.2
2025-11-29 156.8
2025-11-30 421.5
2025-12-01 395.1
2025-12-02 289.4

Этот запрос покажет ежедневный рост таблицы: сколько снапшотов создаётся и сколько данных добавляется каждый день.

Поиск партиций, нуждающихся в обслуживании

-- Каким партициям требуется сжатие?SELECT  partition,  file_count,  CASE    WHEN file_count > 100 THEN 'NEEDS COMPACTION'    WHEN AVG(file_size_in_bytes)/1024/1024 < 10 THEN 'SMALL FILES'    ELSE 'OK'  END as actionFROM sales.filesGROUP BY partitionHAVING file_count > 100 OR AVG(file_size_in_bytes)/1024/1024 < 10;
partition file_count action
{"sale_date_month": 669, "region": "US"} 247 NEEDS COMPACTION
{"sale_date_month": 670, "region": "APAC"} 183 NEEDS COMPACTION
{"sale_date_month": 667, "region": "EMEA"} 156 NEEDS COMPACTION
{"sale_date_month": 668, "region": "US"} 128 NEEDS COMPACTION
{"sale_date_month": 665, "region": "LATA"} 87 SMALL FILES
{"sale_date_month": 671, "region": "APAC"} 73 SMALL FILES
{"sale_date_month": 662, "region": "EMEA"} 52 SMALL FILES

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

Отслеживание веток и тегов

-- ОтслеиSELECT  name,  type,  snapshot_id,  max_reference_age_in_ms/86400000 as retention_daysFROM sales.refs
name type snapshot_id retention_days
main BRANCH 8829603393873253991 null
staging BRANCH 8829603393873253987 7.0
backup_2024_q4 TAG 8829603393873253945 90.0
pre_migration TAG 8829603393873253921 30.0
dev_feature_x BRANCH 8829603393873253978 3.0
audit_snapshot TAG 8829603393873253889 365.0

Показывает все ветки и теги с привязкой к снапшотам и датам их создания.

Отладка и советы для продакшена

Давайте применим эти таблицы на практике для решения некоторых реально звучащих проблем.

Первый запрос: ваша таблица выросла на 500 гигабайт за ночь. Да, кажется плохо. Что случилось? Этот запрос сразу показывает, в какой день был необычный рост. И внезапно да, пятница очень большая, суббота очень большая, воскресенье немного меньше, но вы можете увидеть начало динамики праздничного сезона. Так что, возможно, это не что‑то сломанное в пайплайне, а просто очень удачный год. Но это даёт вам некоторое понимание.

Второй запрос: какие партиции нуждаются в обслуживании? Вместо догадок вы можете получить точный список партиций, у которых слишком много файлов и которые, возможно, нуждаются в компактификации. И мы определим это здесь как более 100 файлов на партицию или файлы, которые слишком малы (средний размер меньше 10 мегабайт). Это может быть проблемой. Так что, если вы просмотрите этот запрос, у нас есть случай, когда количество файлов больше 100 и средний размер меньше 10 мегабайт. Это называется «мелкие файлы», и мы получаем эту хорошую колонку action: needs_compaction_small_files. Это небольшой анализ партиций прямо из одного запроса.

Третий запрос: отслеживайте ваши ветки и теги с их политиками удержания. Вы действительно можете запускать эти запросы ежедневно в продакшене. Расследования, которые занимали часы, теперь занимают минуты. Вы можете просто заметить эти вещи. Те, которые подлежат очистке, — всё из метатаблицы refs.

Советы по использованию метатаблиц в продакшене

Несколько вещей:

  • Создавайте представления (views) для запросов, которые вы запускаете часто. Например, проверки здоровья, тренды роста, анализ партиций — это удобная вещь, которую стоит иметь в своём арсенале.
  • Настраивайте алерты, когда количество файлов достигает порогов. Вы можете легко получить количество файлов из метатаблиц.
  • Автоматизируйте ежедневные проверки здоровья. Мы видели несколько примеров этого.
  • Документируйте то, что находите. Это отлично подходит для планирования мощностей. Вы сможете легко получить эти результаты и поделиться ими.

И эти запросы — очень важный момент — дёшевые. Они читают крошечные файлы метаданных, а не ваши фактические данные. Так что это не будет дорогостоящими операциями. И действительно, вам стоит рассмотреть возможность сделать их частью вашего ежедневного workflow.

Метатаблицы дают вам видимость того, что происходит внутри Iceberg. Сложная отладка превращается в простой SQL. В некоторых случаях — умеренно интересный SQL, но вы можете это сделать. Это то, что вы делаете. Это база данных. Нет никаких догадок о состоянии таблицы — просто запросите метаданные.

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


«Метатаблицы Iceberg — это как рентген для ваших данных: можно заглянуть внутрь, не вскрывая пациента. Только не удивляйтесь, если обнаружите, что некоторые файлы ведут себя странно — это нормально для данных, которые живут своей жизнью.»


На этом пока всё

Вы завершили пятую часть курса Apache Iceberg! Вы освоили тегирование и ветвление — Git‑подобный workflow с тегами, ветками, fast‑forward мержами и Write‑Audit‑Publish, а также научились анализировать внутреннее состояние таблиц через системные метатаблицы. Отличный прогресс!

Что будет дальше? В шестой, заключительной части курса мы перейдём к финальным темам:

  • Обслуживание таблиц — удаление старых снапшотов, компактификация, очистка метаданных.
  • Движки запросов и экосистема — обзор Spark, Flink, Trino, облачных сервисов и Python.

Чтобы не пропустить выход новых уроков:

Спасибо, что учитесь с нами! 🚀

← Назад к упражнению по ветвлению