Si está trabajando con grandes bases de datos en Postgres , esta historia le resultará familiar. A medida que su base de datos de Postgres sigue creciendo, su rendimiento comienza a disminuir y comienza a preocuparse por el espacio de almacenamiento o, para ser precisos, cuánto pagará por él. Te encanta PostgreSQL, pero hay algo que desearías tener: un mecanismo de compresión de datos altamente efectivo.
PostgreSQL tiene una especie de mecanismo de compresión:
Incluso si pudiera reducir el tamaño de los conjuntos de datos, TOAST (La técnica de almacenamiento de atributos de gran tamaño) no es el mecanismo tradicional de compresión de datos. Para entender qué es TOAST, tenemos que empezar hablando de
Las unidades de almacenamiento de Postgres se llaman páginas y tienen un tamaño fijo (8 kB por defecto). Tener un tamaño de página fijo le brinda a Postgres muchas ventajas, a saber, su simplicidad, eficiencia y coherencia en la gestión de datos, pero tiene una desventaja: es posible que algunos valores de datos no quepan en esa página.
Aquí es donde entra TOAST. TOAST se refiere al mecanismo automático que utiliza PostgreSQL para almacenar y administrar de manera eficiente valores en Postgres que no caben dentro de una página. Para manejar dichos valores, Postgres TOAST, de forma predeterminada, los comprimirá utilizando un algoritmo interno. Si, después de la compresión, los valores siguen siendo demasiado grandes, Postgres los moverá a una tabla separada (llamada tabla TOAST), dejando los punteros en la tabla original.
Como veremos más adelante en este artículo, usted puede modificar esta estrategia como usuario, por ejemplo, diciéndole a Postgres que evite comprimir datos en una columna en particular.
Los tipos de datos que podrían estar sujetos a TOAST son principalmente aquellos de longitud variable que tienen el potencial de exceder los límites de tamaño de una página PostgreSQL estándar. Por otro lado, los tipos de datos de longitud fija, como integer
, float
o timestamp
, no están sujetos a TOAST ya que caben cómodamente dentro de una página.
Algunos ejemplos de tipos de datos que podrían estar sujetos a TOAST son:
json
y jsonb
Grandes cadenas text
varchar
y varchar(n)
(si la longitud especificada en varchar(n)
es lo suficientemente pequeña, entonces los valores de esa columna siempre pueden permanecer por debajo del umbral TOAST).
bytea
almacenando datos binarios
Datos geométricos como path
y polygon
y tipos PostGIS como geometry
o geography
Comprender TOAST no sólo se relaciona con el concepto de tamaño de página sino también con otro concepto de almacenamiento de Postgres: las tuplas. Las tuplas son filas en una tabla de PostgreSQL. Normalmente, el mecanismo TOAST se activa si todos los campos dentro de una tupla tienen un tamaño total superior a 2 kB aproximadamente.
Si ha estado prestando atención, es posible que se pregunte: "Espera, pero el tamaño de la página es de alrededor de 8 kB. ¿A qué se debe esta sobrecarga?". Esto se debe a que a PostgreSQL le gusta asegurarse de poder almacenar múltiples tuplas en una sola página: si las tuplas son demasiado grandes, caben menos tuplas en cada página, lo que genera mayores operaciones de E/S y un rendimiento reducido.
Postgres también necesita mantener espacio libre para incluir datos operativos adicionales: cada página almacena no solo los datos de la tupla sino también información adicional para administrar los datos, como identificadores de elementos, encabezados e información de transacciones.
Entonces, cuando el tamaño combinado de todos los campos en una tupla excede aproximadamente 2 kB (o el parámetro de umbral TOAST, como veremos más adelante), PostgreSQL toma medidas para garantizar que los datos se almacenen de manera eficiente. TOAST maneja esto de dos maneras principales:
Compresión. PostgreSQL puede comprimir los valores de campo grandes dentro de la tupla para reducir su tamaño usando un algoritmo de compresión que cubriremos más adelante en este artículo. De forma predeterminada, si la compresión es suficiente para reducir el tamaño total de la tupla por debajo del umbral, los datos permanecerán en la tabla principal, aunque en un formato comprimido.
Almacenamiento fuera de línea. Si la compresión por sí sola no es lo suficientemente efectiva para reducir el tamaño de los valores de campo grandes, Postgres los mueve a una tabla TOAST separada. Este proceso se conoce como almacenamiento "fuera de línea" porque la tupla original en la tabla principal ya no contiene los valores de campo grandes. En cambio, contiene un "puntero" o referencia a la ubicación de los datos grandes en la tabla TOAST.
Estamos simplificando ligeramente las cosas para este artículo.
pglz
Hemos mencionado que TOAST puede comprimir valores grandes en PostgreSQL. Pero, ¿qué algoritmo de compresión utiliza PostgreSQL y qué tan efectivo es?
pglz
(PostgreSQL Lempel-Ziv) es el algoritmo de compresión interna predeterminado utilizado por PostgreSQL diseñado específicamente para TOAST.
Así es como funciona en términos muy simples:
pglz
intenta evitar datos repetidos. Cuando ve datos repetidos, en lugar de escribir lo mismo nuevamente, simplemente señala donde lo escribió antes. Este "evitar la repetición" ayuda a ahorrar espacio.
A medida que pglz
lee los datos, recuerda un poco de los datos recientes que ha visto. Este recuerdo reciente se conoce como la "ventana deslizante".
A medida que llegan nuevos datos, pglz
comprueba si ha visto estos datos recientemente (dentro de su ventana deslizante). En caso afirmativo, escribe una breve referencia en lugar de repetir los datos.
Si los datos son nuevos o no se repiten suficientes veces como para hacer una referencia más corta que los datos reales, pglz
simplemente los escribe tal como están.
Cuando llega el momento de leer los datos comprimidos, pglz
usa sus referencias para recuperar los datos originales. Este proceso es bastante directo, ya que busca los datos referidos y los coloca donde corresponde.
pglz
no necesita almacenamiento separado para su memoria (la ventana deslizante); lo construye sobre la marcha mientras lo comprime y hace lo mismo cuando lo descomprime.
Esta implementación está diseñada para ofrecer un equilibrio entre la eficiencia de la compresión y la velocidad dentro del mecanismo TOAST. En términos de tasa de compresión, la efectividad de pglz
dependerá en gran medida de la naturaleza de los datos.
Por ejemplo, los datos muy repetitivos se comprimen mucho mejor que los datos de alta entropía (como los datos aleatorios). Es posible que vea índices de compresión en el rango del 25 al 50 por ciento, pero esta es una estimación muy general: los resultados variarán ampliamente según la naturaleza exacta de los datos.
De forma predeterminada, PostgreSQL pasará por el mecanismo TOAST de acuerdo con el procedimiento explicado anteriormente (primero la compresión y luego el almacenamiento fuera de línea, si la compresión no es suficiente). Aún así, puede haber escenarios en los que desee ajustar este comportamiento columna por columna. PostgreSQL le permite hacer esto utilizando las estrategias TOAST PLAIN
, EXTERNAL
, EXTENDED
y MAIN
.
EXTENDED
: Esta es la estrategia predeterminada. Implica que los datos se almacenarán fuera de línea en una tabla TOAST separada si es demasiado grande para una página de tabla normal. Antes de mover los datos a la tabla TOAST, se comprimirán para ahorrar espacio.
EXTERNAL
: Esta estrategia le dice a PostgreSQL que almacene los datos de esta columna fuera de línea si los datos son demasiado grandes para caber en una página de tabla normal, y le pedimos a PostgreSQL que no comprima los datos; el valor simplemente se moverá al Mesa TOAST tal como está.
MAIN
: Esta estrategia es un término medio. Intenta mantener los datos alineados en la tabla principal mediante compresión; si los datos son definitivamente demasiado grandes, los moverá a la tabla TOAST para evitar un error, pero PostgreSQL no moverá los datos comprimidos. En cambio, almacenará el valor en la tabla TOAST en su forma original.
PLAIN
: Usar PLAIN
en una columna le dice a PostgreSQL que siempre almacene los datos de la columna en línea en la tabla principal, asegurando que no se muevan a una tabla TOAST fuera de línea. Tenga en cuenta que si los datos superan el tamaño de la página, INSERT
fallará porque los datos no caben.
Si desea inspeccionar las estrategias actuales de una tabla en particular, puede ejecutar lo siguiente:
\d+ your_table_name
Obtendrás un resultado como este:
=> \d+ example_table Table "public.example_table" Column | Data Type | Modifiers | Storage | Stats target | Description ---------+------------------+-----------+----------+--------------+------------- bar | varchar(100000) | | extended | |
Si desea modificar la configuración de almacenamiento, puede hacerlo usando el siguiente comando:
-- Sets EXTENDED as the TOAST strategy for bar_column ALTER TABLE example_blob ALTER COLUMN bar_column SET STORAGE EXTENDED;
Aparte de las estrategias anteriores, estos dos parámetros también son importantes para controlar el comportamiento de TOAST:
TOAST_TUPLE_THRESHOLD
Este es el parámetro que establece el umbral de tamaño para cuando se consideran operaciones TOASTing (compresión y almacenamiento fuera de línea) para tuplas de gran tamaño.
Como mencionamos anteriormente, de forma predeterminada, TOAST_TUPLE_THRESHOLD
está configurado en aproximadamente 2 kB.
TOAST_COMPRESSION_THRESHOLD
Este es el parámetro que especifica el tamaño mínimo de un valor antes de que Postgres considere comprimirlo durante el proceso TOASTing.
Si un valor supera este umbral, PostgreSQL intentará comprimirlo. Sin embargo, el hecho de que un valor esté por encima del umbral de compresión no significa automáticamente que se comprimirá: las estrategias TOAST guiarán a PostgreSQL sobre cómo manejar los datos en función de si se comprimieron y su tamaño resultante en relación con la tupla y límites de páginas, como veremos en la siguiente sección.
TOAST_TUPLE_THRESHOLD
es el punto de activación. Cuando el tamaño de los campos de datos de una tupla combinados excede este umbral, PostgreSQL evaluará cómo administrarlo en función de la estrategia TOAST establecida para sus columnas, considerando la compresión y el almacenamiento fuera de línea. Las acciones exactas que se tomen también dependerán de si los datos de la columna superan el TOAST_COMPRESSION_THRESHOLD
:
EXTENDED
(estrategia predeterminada): si el tamaño de una tupla excede TOAST_TUPLE_THRESHOLD
, PostgreSQL primero intentará comprimir las columnas de gran tamaño si también exceden TOAST_COMPRESSION_THRESHOLD
. Si la compresión reduce el tamaño de la tupla por debajo del umbral, permanecerá en la tabla principal. Si no es así, los datos se moverán a una tabla TOAST fuera de línea y la tabla principal contendrá punteros a estos datos externos.
MAIN
: Si el tamaño de la tupla supera TOAST_TUPLE_THRESHOLD
, PostgreSQL intentará comprimir las columnas de gran tamaño (siempre que superen TOAST_COMPRESSION_THRESHOLD
). Si la compresión permite que la tupla quepa dentro de la tupla de la tabla principal, permanece allí. De lo contrario, los datos se mueven a la tabla TOAST en su forma sin comprimir.
EXTERNAL
: PostgreSQL omite la compresión, independientemente de TOAST_COMPRESSION_THRESHOLD
. Si el tamaño de la tupla supera TOAST_TUPLE_THRESHOLD
, las columnas de gran tamaño se almacenarán fuera de línea en la tabla TOAST.
PLAIN
: Los datos siempre se almacenan en la tabla principal. Si el tamaño de una tupla excede el tamaño de la página (debido a que tiene columnas muy grandes), se genera un error.
Estrategia | Comprimir si tupla > TOAST_COMPRESSION_THRESHOLD | Almacenar fuera de línea si tupla > TOAST_TUPLE_THRESHOLD | Descripción |
---|---|---|---|
EXTENDIDO | Sí | Sí | Estrategia por defecto. Primero comprime y luego comprueba si se necesita almacenamiento fuera de línea. |
PRINCIPAL | Sí | Sólo en forma sin comprimir | Primero se comprime y, si aún es demasiado grande, se mueve a la tabla TOAST sin comprimir. |
EXTERNO | No | Sí | Siempre pasa a TOSTAR si es demasiado grande, sin compresión. |
PLANO | No | No | Los datos siempre permanecen en la tabla principal. Si una tupla excede el tamaño de la página, se produce un error. |
A estas alturas, probablemente comprenderá por qué TOAST no es el mecanismo de compresión de datos que desearía tener en PostgreSQL. Las aplicaciones modernas implican la ingesta diaria de grandes volúmenes de datos, lo que significa que las bases de datos crecen (sobre)rápidamente.
Este problema no era tan importante cuando se creó nuestro querido Postgres hace décadas, pero los desarrolladores de hoy necesitan soluciones de compresión para reducir la huella de almacenamiento de sus conjuntos de datos.
Si bien TOAST incorpora la compresión como una de sus técnicas, es crucial comprender que su función principal no es servir como mecanismo de compresión de bases de datos en el sentido tradicional. TOAST es principalmente una solución a un problema: gestionar grandes valores dentro de los límites estructurales de una página de Postgres.
Si bien este enfoque puede generar algunos ahorros de espacio de almacenamiento debido a la compresión de valores grandes específicos, su objetivo principal no es optimizar el espacio de almacenamiento en todos los ámbitos.
Por ejemplo, si tienes una base de datos de 5 TB formada por tuplas pequeñas, TOAST no te ayudará a convertir esos 5 TB en 1 TB. Si bien hay parámetros dentro de TOAST que se pueden ajustar, esto no transformará a TOAST en una solución generalizada de ahorro de almacenamiento.
Y existen otros problemas inherentes al uso de TOAST como mecanismo de compresión tradicional en PostgreSQL, por ejemplo:
Acceder a datos TOASTed puede agregar gastos generales, especialmente cuando los datos se almacenan fuera de línea. Esto se vuelve más evidente cuando se accede con frecuencia a muchos textos grandes u otros tipos de datos compatibles con TOAST.
TOAST carece de un mecanismo fácil de usar y de alto nivel para dictar políticas de compresión. No está diseñado para optimizar los costos de almacenamiento ni facilitar la administración del almacenamiento.
La compresión de TOAST no está diseñada para proporcionar relaciones de compresión especialmente altas. Solo utiliza un algoritmo ( pglz
) con tasas de compresión que varían típicamente entre el 25 y el 50 por ciento.
Al agregar una política de compresión a sus tablas grandes,
Al definir una política de compresión basada en el tiempo, indica cuándo se deben comprimir los datos. Por ejemplo, puede optar por comprimir automáticamente los datos de más de siete (7) días:
-- Compress data older than 7 days SELECT add_compression_policy('my_hypertable', INTERVAL '7 days');
A través de esta política de compresión, Timescale transformará la tabla.
Compresión de gorila para flotadores.
Delta de delta +
Compresión de diccionario de filas completas para columnas con algunos valores repetidos (+ compresión LZ en la parte superior)
Compresión de matriz basada en LZ para todos los demás tipos
Este diseño de compresión en columnas ofrece una solución eficiente y escalable al problema de los grandes conjuntos de datos en PostgreSQL. Le permite utilizar menos almacenamiento para almacenar más datos sin perjudicar el rendimiento de su consulta (lo mejora). Y en las últimas versiones de TimescaleDB, también puede INSERT
, DELETE
y UPDATE
directamente sobre datos comprimidos.
Esperamos que este artículo le haya ayudado a comprender que, si bien TOAST es un mecanismo bien pensado para administrar valores grandes dentro de una página de PostgreSQL, no es eficaz para optimizar el uso del almacenamiento de bases de datos en el ámbito de las aplicaciones modernas.
Si está buscando una compresión de datos eficaz que pueda aumentar sus ahorros de almacenamiento, pruebe Timescale. Puede probar nuestra plataforma en la nube que impulsa PostgreSQL a nuevos niveles de rendimiento, haciéndolo más rápido y potente.
Escrito por Carlota Soto .