Если вы работаете с большими базами данных в Postgres , эта история покажется вам знакомой. По мере того как ваша база данных Postgres продолжает расти, ваша производительность начинает снижаться, и вы начинаете беспокоиться о месте хранения — или, точнее, о том, сколько вы за него заплатите. Вы любите PostgreSQL, но есть кое-что, что вам хотелось бы: высокоэффективный механизм сжатия данных.
PostgreSQL имеет своего рода механизм сжатия:
Даже если TOAST (метод хранения негабаритных атрибутов) может уменьшить размер наборов данных, он не является традиционным механизмом сжатия данных. Чтобы понять, что такое TOAST, нам нужно начать с разговора о
Единицы хранения Postgres называются страницами и имеют фиксированный размер (по умолчанию 8 КБ). Наличие фиксированного размера страницы дает Postgres множество преимуществ, а именно простоту, эффективность и согласованность управления данными, но у него есть и обратная сторона: некоторые значения данных могут не поместиться на этой странице.
Именно здесь на помощь приходит TOAST. TOAST — это автоматический механизм, который PostgreSQL использует для эффективного хранения и управления значениями в Postgres, которые не умещаются на странице. Для обработки таких значений Postgres TOAST по умолчанию сжимает их, используя внутренний алгоритм. Если после сжатия значения по-прежнему слишком велики, Postgres переместит их в отдельную таблицу (называемую таблицей TOAST), оставив указатели в исходной таблице.
Как мы увидим далее в этой статье, вы можете изменить эту стратегию как пользователь, например, указав Postgres избегать сжатия данных в определенном столбце.
Типы данных, которые могут подвергаться TOAST, в основном имеют переменную длину и могут превысить ограничения размера стандартной страницы PostgreSQL. С другой стороны, типы данных фиксированной длины, такие как integer
, float
или timestamp
, не подвергаются TOAST, поскольку они удобно помещаются на странице.
Некоторые примеры типов данных, которые могут подвергаться TOAST:
json
и jsonb
Большие text
строки
varchar
и varchar(n)
(если длина, указанная в varchar(n)
достаточно мала, значения этого столбца могут всегда оставаться ниже порога TOAST.)
bytea
хранит двоичные данные
Геометрические данные, такие как path
и polygon
, и типы PostGIS, такие как geometry
или geography
Понимание TOAST связано не только с концепцией размера страницы, но и с другой концепцией хранения данных Postgres: кортежами. Кортежи — это строки в таблице PostgreSQL. Обычно механизм TOAST срабатывает, если общий размер всех полей в кортеже превышает 2 КБ.
Если вы обратили внимание, вы, возможно, задаетесь вопросом: «Подождите, но размер страницы составляет около 8 КБ — почему такие накладные расходы?» Это связано с тем, что PostgreSQL предпочитает хранить несколько кортежей на одной странице: если кортежи слишком велики, на каждой странице помещается меньше кортежей, что приводит к увеличению количества операций ввода-вывода и снижению производительности.
Postgres также необходимо сохранять свободное пространство для размещения дополнительных операционных данных: на каждой странице хранятся не только данные кортежа, но и дополнительная информация для управления данными, такая как идентификаторы элементов, заголовки и информация о транзакциях.
Итак, когда совокупный размер всех полей в кортеже превышает примерно 2 КБ (или пороговый параметр TOAST, как мы увидим позже), PostgreSQL предпринимает действия, чтобы гарантировать эффективное хранение данных. TOAST решает эту проблему двумя основными способами:
Сжатие. PostgreSQL может сжимать большие значения полей в кортеже, чтобы уменьшить их размер, используя алгоритм сжатия, который мы рассмотрим позже в этой статье. По умолчанию, если сжатия достаточно, чтобы общий размер кортежа стал ниже порогового значения, данные останутся в основной таблице, хотя и в сжатом формате.
Внеочередное хранение. Если одно только сжатие недостаточно эффективно для уменьшения размера больших значений полей, Postgres перемещает их в отдельную таблицу TOAST. Этот процесс известен как «внеочередное» хранение, поскольку исходный кортеж в основной таблице больше не содержит больших значений полей. Вместо этого он содержит «указатель» или ссылку на расположение больших данных в таблице TOAST.
В этой статье мы немного упрощаем ситуацию:
pglz
Мы упоминали, что TOAST может сжимать большие значения в PostgreSQL. Но какой алгоритм сжатия использует PostgreSQL и насколько он эффективен?
pglz
(PostgreSQL Lempel-Ziv) — это внутренний алгоритм сжатия по умолчанию, используемый PostgreSQL, специально разработанный для TOAST.
Вот как это работает очень простыми словами:
pglz
пытается избежать повторения данных. Когда он видит повторяющиеся данные, вместо того, чтобы писать одно и то же снова, он просто указывает туда, где он писал это раньше. Такое «избегание повторений» помогает сэкономить место.
Когда pglz
считывает данные, он запоминает часть недавно просмотренных данных. Это недавнее воспоминание называется «скользящим окном».
По мере поступления новых данных pglz
проверяет, видел ли он эти данные в последнее время (в пределах своего скользящего окна). Если да, он записывает короткую ссылку вместо повторения данных.
Если данные новые или повторяются недостаточное количество раз, чтобы сделать ссылку короче фактических данных, pglz
просто записывает их как есть.
Когда приходит время прочитать сжатые данные, pglz
использует свои ссылки для получения исходных данных. Этот процесс довольно прямой, поскольку он ищет указанные данные и помещает их туда, где им место.
pglz
не требует отдельного хранилища для своей памяти (скользящее окно); он создает его на ходу во время сжатия и делает то же самое при распаковке.
Эта реализация предназначена для обеспечения баланса между эффективностью сжатия и скоростью в рамках механизма TOAST. Что касается степени сжатия, эффективность pglz
во многом будет зависеть от характера данных.
Например, часто повторяющиеся данные будут сжиматься гораздо лучше, чем данные с высокой энтропией (например, случайные данные). Вы можете увидеть степень сжатия в диапазоне от 25 до 50 процентов, но это очень общая оценка — результаты будут сильно различаться в зависимости от точного характера данных.
По умолчанию PostgreSQL использует механизм TOAST в соответствии с процедурой, описанной ранее (сначала сжатие, затем внешнее сохранение, если сжатия недостаточно). Тем не менее, могут быть сценарии, в которых вам может потребоваться более тонкая настройка этого поведения для каждого столбца. PostgreSQL позволяет вам сделать это, используя стратегии TOAST PLAIN
, EXTERNAL
, EXTENDED
и MAIN
.
EXTENDED
: это стратегия по умолчанию. Это означает, что данные будут храниться вне очереди в отдельной таблице TOAST, если они слишком велики для обычной страницы таблицы. Перед перемещением данных в таблицу TOAST они будут сжаты для экономии места.
EXTERNAL
: эта стратегия сообщает PostgreSQL хранить данные для этого столбца вне строки, если данные слишком велики, чтобы поместиться на обычной странице таблицы, и мы просим PostgreSQL не сжимать данные — значение будет просто перемещено в Стол TOAST как есть.
MAIN
: Эта стратегия представляет собой золотую середину. Он пытается сохранить соответствие данных в основной таблице посредством сжатия; если данные определенно слишком велики, они будут перемещены в таблицу TOAST, чтобы избежать ошибки, но PostgreSQL не будет перемещать сжатые данные. Вместо этого оно сохранит значение в таблице TOAST в исходной форме.
PLAIN
: использование PLAIN
в столбце указывает PostgreSQL всегда хранить данные столбца в строке в основной таблице, гарантируя, что они не будут перемещены в внестрочную таблицу TOAST. Учтите, что если данные превысят размер страницы, INSERT
завершится неудачей, поскольку данные не поместятся.
Если вы хотите проверить текущие стратегии конкретной таблицы, вы можете запустить следующее:
\d+ your_table_name
Вы получите такой вывод:
=> \d+ example_table Table "public.example_table" Column | Data Type | Modifiers | Storage | Stats target | Description ---------+------------------+-----------+----------+--------------+------------- bar | varchar(100000) | | extended | |
Если вы хотите изменить настройки хранилища, вы можете сделать это с помощью следующей команды:
-- Sets EXTENDED as the TOAST strategy for bar_column ALTER TABLE example_blob ALTER COLUMN bar_column SET STORAGE EXTENDED;
Помимо описанных выше стратегий, эти два параметра также важны для управления поведением TOAST:
TOAST_TUPLE_THRESHOLD
Это параметр, который устанавливает порог размера, когда операции TOAST (сжатие и внешнее хранение) рассматриваются для кортежей слишком большого размера.
Как мы упоминали ранее, по умолчанию TOAST_TUPLE_THRESHOLD
имеет значение примерно 2 КБ.
TOAST_COMPRESSION_THRESHOLD
Это параметр, который определяет минимальный размер значения, прежде чем Postgres рассмотрит возможность его сжатия во время процесса TOAST.
Если значение превышает этот порог, PostgreSQL попытается его сжать. Однако тот факт, что значение превышает порог сжатия, не означает, что оно автоматически будет сжато: стратегии TOAST будут указывать PostgreSQL, как обрабатывать данные в зависимости от того, были ли они сжаты, и их результирующего размера относительно кортежа и ограничения на количество страниц, как мы увидим в следующем разделе.
TOAST_TUPLE_THRESHOLD
— это точка срабатывания. Когда совокупный размер полей данных кортежа превышает этот порог, PostgreSQL оценит, как им управлять, на основе установленной стратегии TOAST для его столбцов, учитывая сжатие и внешнее хранение. Точные предпринятые действия также будут зависеть от того, превосходят ли данные столбца TOAST_COMPRESSION_THRESHOLD
:
EXTENDED
(стратегия по умолчанию): если размер кортежа превышает TOAST_TUPLE_THRESHOLD
, PostgreSQL сначала попытается сжать слишком большие столбцы, если они также превышают TOAST_COMPRESSION_THRESHOLD
. Если при сжатии размер кортежа станет ниже порогового значения, он останется в основной таблице. В противном случае данные будут перемещены во внешнюю таблицу TOAST, а основная таблица будет содержать указатели на эти внешние данные.
MAIN
: если размер кортежа превышает TOAST_TUPLE_THRESHOLD
, PostgreSQL попытается сжать столбцы слишком большого размера (при условии, что они превышают TOAST_COMPRESSION_THRESHOLD
). Если сжатие позволяет кортежу поместиться в кортеж основной таблицы, он остается там. Если нет, данные перемещаются в таблицу TOAST в несжатом виде.
EXTERNAL
: PostgreSQL пропускает сжатие независимо от TOAST_COMPRESSION_THRESHOLD
. Если размер кортежа превышает TOAST_TUPLE_THRESHOLD
, столбцы слишком большого размера будут храниться вне строки в таблице TOAST.
PLAIN
: данные всегда хранятся в основной таблице. Если размер кортежа превышает размер страницы (из-за очень больших столбцов), возникает ошибка.
Стратегия | Сжать кортеж if > TOAST_COMPRESSION_THRESHOLD | Сохранять вне очереди, если кортеж > TOAST_TUPLE_THRESHOLD | Описание |
---|---|---|---|
РАСШИРЕННЫЙ | Да | Да | Стратегия по умолчанию. Сначала сжимает, затем проверяет, требуется ли внешнее хранилище. |
ОСНОВНОЙ | Да | Только в несжатом виде | Сначала сжимается, а если размер по-прежнему слишком велик, перемещается в таблицу TOAST без сжатия. |
ВНЕШНИЙ | Нет | Да | Всегда переходит в режим TOAST, если размер слишком велик, без сжатия. |
ПРОСТОЙ | Нет | Нет | Данные всегда остаются в основной таблице. Если кортеж превышает размер страницы, возникает ошибка. |
К настоящему моменту вы, вероятно, поймете, почему TOAST — это не тот механизм сжатия данных, который вы хотели бы иметь в PostgreSQL. Современные приложения подразумевают, что ежедневно обрабатываются большие объемы данных, а это означает, что базы данных быстро (пере)растут.
Такая проблема не была столь заметной, когда десятилетия назад был создан наш любимый Postgres, но сегодняшним разработчикам нужны решения для сжатия, позволяющие уменьшить объем хранилища их наборов данных.
Хотя TOAST включает сжатие в качестве одного из своих методов, важно понимать, что его основная роль не заключается в том, чтобы служить механизмом сжатия базы данных в традиционном смысле. TOAST — это, главным образом, решение одной проблемы: управление большими значениями в структурных рамках страницы Postgres.
Хотя этот подход может привести к некоторой экономии места для хранения за счет сжатия определенных больших значений, его основная цель не состоит в оптимизации пространства для хранения по всем направлениям.
Например, если у вас есть база данных размером 5 ТБ, состоящая из небольших кортежей, TOAST не поможет вам превратить эти 5 ТБ в 1 ТБ. Хотя в TOAST есть параметры, которые можно настраивать, это не превратит TOAST в универсальное решение для экономии места.
Существуют и другие проблемы, присущие использованию TOAST в качестве традиционного механизма сжатия в PostgreSQL, например:
Доступ к данным TOAST может привести к увеличению накладных расходов, особенно если данные хранятся вне очереди. Это становится более очевидным, когда часто осуществляется доступ к большому тексту или другим типам данных, поддерживающим TOAST.
В TOAST отсутствует удобный для пользователя механизм высокого уровня для определения политик сжатия. Он не предназначен для оптимизации затрат на хранение или облегчения управления хранилищем.
Сжатие TOAST не предназначено для обеспечения особенно высоких степеней сжатия. Он использует только один алгоритм ( pglz
) со степенью сжатия, обычно варьирующейся от 25 до 50 процентов.
Добавив политику сжатия в большие таблицы,
Определяя политику сжатия по времени, вы указываете, когда данные следует сжимать. Например, вы можете автоматически сжимать данные старше семи (7) дней:
-- Compress data older than 7 days SELECT add_compression_policy('my_hypertable', INTERVAL '7 days');
С помощью этой политики сжатия Timescale преобразует таблицу.
Компрессия Gorilla для поплавков
Дельта-дельта +
Сжатие словаря всей строки для столбцов с несколькими повторяющимися значениями (+ LZ-сжатие сверху)
Сжатие массива на основе LZ для всех остальных типов
Эта конструкция столбчатого сжатия предлагает эффективное и масштабируемое решение проблемы больших наборов данных в PostgreSQL. Это позволяет вам использовать меньше места для хранения большего количества данных без ущерба для производительности запросов (это улучшает ее). А в последних версиях TimescaleDB вы также можете INSERT
, DELETE
и UPDATE
непосредственно поверх сжатых данных.
Мы надеемся, что эта статья помогла вам понять, что, хотя TOAST — это хорошо продуманный механизм для управления большими значениями на странице PostgreSQL, он неэффективен для оптимизации использования хранилища базы данных в современных приложениях.
Если вы ищете эффективное сжатие данных, которое может значительно увеличить экономию места на хранилище, попробуйте Timescale. Вы можете попробовать нашу облачную платформу, которая выводит PostgreSQL на новый уровень производительности, делая его быстрее и эффективнее.
Автор Карлота Сото .