Введение

Привет, Хабр! Меня зовут Александр, я старший инженер в команде Tantor Labs. За время работы накопилось не мало опыта, поэтому пришло время им делиться.

В мире управления базами данных от эффективного хранения больших объемов информации зависит оптимизация производительности и использования дискового пространства. В этой статье разберем основные методы сжатия данных в 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 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 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 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 | 480 MB
 toast_lz4_table         | pg_toast_5477398 | 297 MB
 toast_default_table     | pg_toast_5477407 | 297 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 на таблице 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 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 | 777 MB

Прирост составил 480 МБ.

Далее посмотрим, с каким типом сжатия хранятся данные в 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 способен обеспечить лучшее сжатие и более быстрое восстановление данных при меньшей нагрузке на процессор.

Рекомендации:

  • Тестируйте методы сжатия на своем наборе данных, чтобы выбрать оптимальный метод сжатия.

  • Рассмотрите возможность использования разных методов сжатия в одной базе данных для максимальной гибкости.

Комментарии (3)


  1. SATORI-LAB
    25.09.2024 15:49

    Спасибо за статью. А есть графики сравнения разных алгоритмов сжатия для разных задач?


    1. dub0v Автор
      25.09.2024 15:49

      Данный тест проводил только с текстовыми данными. Возможно в дальнейшем сделаю более расширенный тест.


  1. suprimex
    25.09.2024 15:49

    Почему бы просто не использовать файловую систему с возможностью сжатия "на-лету" и не размещать там базу с текстовыми данными?