Сжатие данных в PostgreSQL: как различные методы влияют на хранение TOAST
Введение
В мире управления базами данных от эффективного хранения больших объемов информации зависит оптимизация производительности и использования дискового пространства. В этой статье разберем основные методы сжатия данных в TOAST, их эволюцию, плюсы и минусы PGLZ и LZ4 и продемонстрируем базовую работу с TOAST в Postgres. В завершение обсудим, как данные с различными методами сжатия могут храниться в одной TOAST-таблице.
История TOAST и методов сжатия
TOAST (The Oversized-Attribute Storage Technique) — это уникальная система в PostgreSQL, предназначенная для эффективного хранения больших данных, таких как текстовые и бинарные объекты (BLOB).
TOAST ввели в PostgreSQL, начиная с версии 7.1, для решения проблемы хранения данных, которые превышают стандартный размер страницы в 8 КБ. TOAST автоматически перемещает такие большие данные в отдельные таблицы и использует сжатие для минимизации объема хранимых данных.
Первоначально TOAST использовал собственный алгоритм сжатия — PGLZ (PostgreSQL Lempel-Ziv). Однако с момента появления версии PostgreSQL 14 добавили новый метод сжатия — LZ4, который предлагает более быстрые операции сжатия и декомпрессии.
Остановимся подробнее на каждом
Разберем плюсы-минусы и пройдемся по характеристикам алгоритмов. Но перед этим добавлю, что описанные ниже преимущества и недостатки алгоритмов сформировались исключительно как личные выводы на основе тестов и обобщения материалов, с которыми мне довелось ознакомиться. Ваше мнение может не совпадать с моим :)
PGLZ — это алгоритм, основанный на LZ77 (Lempel-Ziv 1977). Он специально оптимизирован для сжатия небольших блоков данных. PGLZ создали для достижения компромисса между степенью сжатия и скоростью выполнения.
Плюсы:
— Простота и стабильность работы.
— Эффективен для сжатия небольших текстов.
— Минимальное влияние на производительность при декомпрессии.
Минусы:
— Низкая скорость сжатия по сравнению с современными алгоритмами.
— Уступает по степени сжатия новым методам, таким как LZ4.
— Неэффективен для сжатия больших объемов данных.
LZ4 — это современный алгоритм сжатия, разработанный Яном Коллет в 2011 году. Он также базируется на LZ77, но существенно оптимизирован для скорости. LZ4 обеспечивает компрессию и декомпрессию значительно быстрее, что особенно важно для работы с большими объемами данных. LZ4 добавили в PostgreSQL в версии 14, которая вышла в сентябре 2021 года. Этот алгоритм был введен как альтернатива стандартному.
Плюсы:
— Высокая скорость сжатия и декомпрессии.
— Более эффективно работает с большими объемами данных.
— Обеспечивает сопоставимый уровень сжатия с PGLZ при существенно меньших временных затратах.
Минусы:
— Может быть менее эффективным по степени сжатия в некоторых сценариях по сравнению с PGLZ.
— Сложность настройки и управления в контексте специфических требований приложения.
Переходим к тестам
Перед началом тестов давайте создадим БД с названием toast_compression_test:
create database toast_compression_test;
\c toast_compression_test
Далее создадим 3 таблицы: со сжатием TOAST lz4, pglz и дефолтную, без явного указания типа сжатия.
CREATE TABLE toast_pglz_table (id SERIAL PRIMARY KEY, large_text_column TEXT COMPRESSION pglz);
CREATE TABLE toast_lz4_table (id SERIAL PRIMARY KEY, large_text_column TEXT COMPRESSION lz4) ;
CREATE TABLE toast_default_table (id SERIAL PRIMARY KEY, large_text_column TEXT);
Теперь наполним таблицы текстовыми данными и сравним затраченное время.
INSERT INTO toast_lz4_table (large_text_column)
SELECT repeat('This is a sample text to generate TOAST data and test lz4 compression.', 10000)
FROM generate_series(1, 100000);
Генерация и вставка данных заняла: 39429,172 мс (00:39,429).
INSERT INTO toast_pglz_table (large_text_column)
SELECT repeat('This is a sample text to generate TOAST data and test pglz compression.', 10000)
FROM generate_series(1, 100000);
Генерация и вставка данных заняла: 329792,912 мс (05:29,793).
INSERT INTO toast_default_table (large_text_column)
SELECT repeat('This is a sample text to generate TOAST data and test default compression.', 10000)
FROM generate_series(1, 100000);
Время вставки в эту таблицу будет различаться в зависимости от выставленного параметра default_toast_compression (на момент вставки параметр был выставлен в lz4, и это заняло 30 секунд).
После того как мы наполнили таблицы данными, превышающими размер текстового поля, посмотрим на размер тостов:
SELECT
main_table.relname AS main_table_name,
toast_table.relname AS toast_table_name,
pg_size_pretty(pg_total_relation_size(toast_table.oid)) AS toast_total_size
FROM pg_class main_table
JOIN pg_class toast_table ON main_table.reltoastrelid = toast_table.oid
JOIN pg_attribute attr ON main_table.oid = attr.attrelid
WHERE main_table.reltoastrelid != 0
AND main_table.relkind = 'r'
AND attr.attnum > 0
AND NOT attr.attisdropped
GROUP BY main_table.relname, toast_table.relname, toast_table.oid, attr.attcompression
ORDER BY main_table_name desc;
После чего получим следующий список:
main_table_name | toast_table_name | toast_total_size
-------------------------+------------------+------------------
toast_pglz_table | pg_toast_5477389 | 820 MB
toast_lz4_table | pg_toast_5477398 | 297 MB
toast_default_table | pg_toast_5477407 | 395 MB
Теперь проверим таблицу toast_default_table на тип сжатия TOAST, т. к. мы явно не задавали тип сжатия на уровне TOAST:
SELECT count(*), pg_column_compression(large_text_column) FROM toast_default_table group by pg_column_compression;
Запрос нам возвращает:
count | pg_column_compression
--------+-----------------------
100000 | lz4
Что соответствует параметру default_toast_compression на момент вставки данных в таблицу.
Внимательные пользователи могли заметить, что поля TOAST при явном указании типа сжатия и без него (используется default_toast_compression) могут иметь разный размер. Это поведение может быть вызвано следующими зависимостями.
Различия в уровне сжатия
Даже если сжатие TOAST по умолчанию установлено на LZ4, явное на то указание может влиять на компрессию данных: привести к более эффективному сжатию, особенно если данные хорошо поддаются такому процессу. Если вы явно указываете сжатие TOAST, оно может быть более оптимизированным для конкретного типа данных.Особенности работы TOAST
PostgreSQL не всегда применяет сжатие TOAST к каждому вставляемому значению. Если данные вставляются без указания сжатия, PostgreSQL может принять решение о том, применять сжатие или нет, на основе размера данных. Если явное сжатие задано, PostgreSQL может сжимать даже те данные, которые в других условиях не сжимал бы. Это может привести к меньшему итоговому размеру данных.Фрагментация и дополнительные расходы
При вставке большого количества строк в таблицу с сжатием TOAST могут возникать дополнительные накладные расходы, связанные с управлением страницами, индексами и другими метаданными. Если сжатие настроено явно, PostgreSQL будет эффективнее управлять этими ресурсами, что приведет к меньшему общему размеру занимаемого места.Различия в алгоритмах сжатия
Когда вы явно задаете сжатие, PostgreSQL использует конкретный алгоритм, который может быть более эффективен, чем тот, который применяется по умолчанию (даже если алгоритм тот же). Это может привести к лучшему сжатию данных.
В итоге даже если используется тот же алгоритм сжатия, явная настройка способна активировать дополнительные оптимизации, которые приводят к лучшему результату сжатия и, следовательно, меньшему занимаемому месту.
После проверки типа сжатия TOAST на таблицах и работы default_toast_compression перейдем к вопросу: как поведет себя TOAST на таблице toast_default_table, если мы поменяем тип сжатия на pglz?
Тестируем TOAST на таблице toast_default_table
Для этого нам понадобится:
alter system set default_toast_compression = pglz; - меняем тип сжатия
select pg_reload_conf(); - перезагрузка
show default_toast_compression; - текущее значение параметра
Вывод запроса:
default_toast_compression
---------------------------
pglz
Далее мы повторно в таблицу toast_default_table вставляем данные:
INSERT INTO toast_default_table (large_text_column)
SELECT repeat('This is a sample text to generate TOAST data and test default compression.', 10000)
FROM generate_series(1, 100000);
Генерация и вставка данных заняла: 372706,261 мс (06:12,706).
Теперь давайте проверим, сколько места занимает TOAST:
main_table_name | toast_table_name | toast_total_size
-------------------------+------------------+------------------
toast_default_table | pg_toast_5477407 | 1187 MB
Прирост составил 792 МБ.
Далее посмотрим, с каким типом сжатия хранятся данные в TOAST:
SELECT count(*), pg_column_compression(large_text_column) FROM toast_default_table group by pg_column_compression;
Вывод запроса:
count | pg_column_compression
--------+-----------------------
100000 | pglz
100000 | lz4
На основе предоставленной информации можно сделать вывод, что в одной TOAST-таблице могут находиться данные, сжатые разными методами. Это возможно, так как TOAST управляет каждым атрибутом отдельно. При создании или обновлении строк PostgreSQL может выбрать другой метод сжатия, основываясь на текущих настройках конфигурации или других условиях.
Заключение
TOAST в PostgreSQL — это мощный инструмент для эффективного управления большими данными. Возможность выбора метода сжатия, будь то PGLZ или LZ4, позволяет гибко настраивать систему в зависимости от требований приложения. Как показано в статье, использование LZ4 обеспечивает значительное улучшение производительности благодаря высокой скорости сжатия и декомпрессии, что особенно полезно при работе с большими объемами текстовых данных или в системах с ограниченными вычислительными ресурсами.
Когда использовать PGLZ:
Когда важна стабильность и проверенная временем технология. PGLZ уже давно используется в PostgreSQL и хорошо зарекомендовал себя для небольших текстов и в ситуациях, где производительность декомпрессии более критична, чем скорость сжатия.
Для небольших данных, где важна производительность декомпрессии.
Когда использовать LZ4:
Когда важна скорость обработки данных. LZ4 особенно полезен в системах, где данные часто читаются и обновляются и где необходимо минимизировать задержки при работе с большими объемами информации.
При работе с большими объемами данных, где LZ4 способен обеспечить лучшее сжатие и более быстрое восстановление данных при меньшей нагрузке на процессор.
Рекомендации:
Тестируйте методы сжатия на своем наборе данных, чтобы выбрать оптимальный метод сжатия.
Рассмотрите возможность использования разных методов сжатия в одной базе данных для максимальной гибкости.