Spark
Средний уровеньПочему мои таблицы Delta/Iceberg замедляются каждую неделю, хотя запрос не менялся?
Запрос не изменился. А таблица под ним — да: каждая микропакетная запись добавляет новые мелкие файлы, и время сканирования зависит от числа файлов почти так же, как от объёма данных.
Таблица, в которую стриминговая задача пишет каждые пять минут, накапливает тысячи мелких файлов в месяц — и каждый запрос к ней платит накладные расходы на файл, сколько бы данных в нём ни было.
Откуда на самом деле берутся мелкие файлы
Стриминговые и микропакетные writer'ы коммитят новый файл (часто несколько — по одному на затронутую партицию) при каждом триггере. При триггере раз в 5 минут это сотни файлов в день на партицию — каждый маленький, каждый добавляет собственные накладные расходы на открытие и чтение метаданных при каждом будущем сканировании, независимо от того, сколько данных он реально содержит.
Что чинит, а что не чинит OPTIMIZE/компакция
Компакция переписывает множество мелких файлов в меньшее число крупных — это и есть то, что реально чинит время сканирования. Чего она не делает: не возвращает дисковое пространство — старые и новые файлы должны сосуществовать, поскольку старые снэпшоты таблицы (используемые для time-travel) всё ещё ссылаются на оригиналы — и не чинит изначально неверную схему партиционирования.
VACUUM — отдельный, более рискованный шаг
VACUUM — это то, что реально удаляет файлы, на которые больше не ссылается текущий снэпшот таблицы, после окна хранения — именно этот шаг возвращает стоимость хранения. Слишком короткое окно хранения может удалить файлы, которые всё ещё нужны параллельному читателю или выполняющемуся time-travel запросу, поэтому это отдельная, осознанная команда, а не то, что компакция запускает автоматически.
Посмотрите, как это выглядит на вашем собственном пайплайне.
Загрузите реальный event log Spark, run_results.json от dbt или экспорт метрик Flink — и получите конкретные рекомендации, которые нужно одобрить, а не ещё одно эмпирическое правило.