Прямой ответ
Колоночный формат хранит данные по столбцам, поэтому значения одного столбца однородны и сжимаются эффективнее, чем в построчном формате. Сжатие выполняется на уровне блока столбца выбранным кодеком.
| Кодеки Parquet | Характер |
|---|---|
| snappy | Быстрое сжатие, умеренный коэффициент |
| gzip | Среднее сжатие, средняя скорость |
| zstd | Высокий коэффициент, регулируемая скорость |
| lz4 | Быстрое сжатие, низкий коэффициент |
import pyarrow as pa
import pyarrow.parquet as pq
table = pa.Table.from_pandas(df)
pq.write_table(
table,
"data.zstd.parquet",
compression="zstd",
compression_level=9,
row_group_size=100_000,
)
Кодек указывается при записи, поэтому файл, записанный с одним кодеком, читается независимо от настроек чтения. О выборе кодека по соотношению параметров — в статье про алгоритмы сжатия.
Кодирование значений и размер блока
Сжатие в колоночном формате выполняется в два этапа, и оба влияют на результат.
Кодирование значений. Однородные значения столбца кодируются эффективно: повторяющиеся значения заменяются ссылками, последовательные числа — разностями. Кодирование применяется до сжатия кодеком, поэтому коэффициент определяется обоими этапами.
Размер блока. Данные делятся на группы строк, каждая из которых сжимается отдельно. Малый блок уменьшает объём читаемых данных при выборке, но снижает коэффициент сжатия, поскольку шаблон повторяется на меньшем объёме.
Практическое следствие: размер блока выбирается по характеру запросов. Запросы, читающие малую долю строк, выигрывают от малого блока; запросы, читающие весь столбец, — от большого.
Отдельный аспект — сравнение с построчным форматом. Тот же набор данных в формате CSV занимает больше места, поскольку значения разных типов чередуются в строке и однородность нарушается; о сравнении форматов — в статье про CSV и Parquet.
Три признака неэффективного сжатия в колоночном формате.
Столбец с высокой кардинальностью и случайными значениями. Кодирование не находит шаблонов, поэтому коэффициент близок к единице.
Слишком малый размер блока. Заголовок блока занимает фиксированный объём, поэтому на малых блоках доля заголовка заметна.
Уже сжатые значения в столбце. Бинарные данные, которые уже сжаты, не дают выигрыша при повторном сжатии кодеком.
О влиянии колоночного хранения на скорость аналитических запросов — в статье про колоночные хранилища.
Практика: настройка сжатия в колоночном формате
1. Выберите кодек по ограничению. Быстрый кодек подходит для частой записи, кодеком с высоким коэффициентом — для архивации.
2. Измерьте коэффициент на своих данных. Однородность столбцов определяет коэффициент, поэтому результат зависит от состава данных.
3. Задайте размер блока по характеру запросов. Малый блок сокращает объём чтения при выборке, большой повышает коэффициент.
4. Проверяйте тип столбца. Тип данных влияет на кодирование, поэтому корректный тип даёт лучшее сжатие.
5. Не сжимайте уже сжатые значения. Бинарные данные без избыточности не дают выигрыша при повторном сжатии.
6. Сравнивайте форматы на одном наборе. Различие объёма между форматами определяется и хранением, и сжатием.
7. Фиксируйте параметры записи. Кодек и размер блока задаются явно, чтобы файлы, записанные в разное время, были сопоставимы.
Рекомендации:
- Различайте сжатие и кодирование. Кодирование устраняет избыточность представления, сжатие кодеком уменьшает объём результата.
- Учитывайте стоимость чтения. Распаковка блока выполняется при чтении, поэтому кодек влияет на время запроса.
- Проверяйте совместимость кодека. Потребитель данных должен поддерживать кодек, которым записан файл.
- Не выбирайте максимальный уровень по умолчанию. Прирост коэффициента на высоких уровнях уменьшается, а время записи растёт.
- Пересматривайте параметры при изменении данных. Изменение состава столбцов изменяет однородность и коэффициент сжатия.
Практический сценарий: файл занимал больше ожидаемого
Контекст: файл в колоночном формате оказался значительно больше, чем предполагалось по объёму данных.
- Диагностика. Столбец с идентификатором события содержал случайные значения высокой кардинальности. Кодирование не находило шаблонов, поэтому коэффициент сжатия по этому столбцу был близок к единице, а столбец составлял заметную долю объёма файла.
- Причина. Ожидание коэффициента сжатия строилось по текстовым столбцам с повторяющимися значениями. Столбец со случайными значениями сжимается плохо, и это не было учтено при оценке объёма.
- Действия. (а) Измерили коэффициент сжатия по каждому столбцу и определили столбцы с низким коэффициентом; (б) изменили представление идентификатора: разделили на компоненты, которые кодируются эффективнее; (в) увеличили размер блока, поскольку запросы читали весь столбец, а не выборку; (г) сравнили кодеки на фактических данных и выбрали подходящий по соотношению; (д) зафиксировали параметры записи в коде формирования файла.
- Результат. Объём файла сократился, поскольку столбцы кодируются эффективнее, а размер блока соответствует характеру запросов.
Вывод: коэффициент сжатия в колоночном формате определяется однородностью значений столбца. Столбцы со случайными значениями сжимаются плохо, поэтому оценка объёма строится по измерению каждого столбца.
FAQ
Почему колоночный формат сжимается лучше построчного? Значения одного столбца однородны, поэтому кодирование находит шаблоны. В построчном формате значения разных типов чередуются, и однородность нарушается.
Какой кодек выбрать для аналитических данных? Определяется измерением на собственных данных. Быстрый кодек подходит для частой записи, кодеком с высоким коэффициентом — для хранения с редким чтением.
Влияет ли размер блока на коэффициент сжатия? Да, малый блок снижает коэффициент, поскольку шаблон повторяется на меньшем объёме, но сокращает объём чтения при выборке.
Нужно ли указывать кодек при чтении файла? Нет, кодек записан в метаданных файла, поэтому чтение выполняется с параметрами записи.
Источники: Apache Parquet docs, Arrow Parquet, DuckDB Parquet — ссылки в шапке.