Se você estiver trabalhando com grandes bancos de dados no Postgres , esta história lhe parecerá familiar. À medida que seu banco de dados Postgres continua crescendo, seu desempenho começa a diminuir e você começa a se preocupar com espaço de armazenamento – ou, para ser mais preciso, quanto pagará por ele. Você adora o PostgreSQL, mas há algo que gostaria de ter: um mecanismo de compactação de dados altamente eficaz.
O PostgreSQL possui um mecanismo de compactação:
Mesmo que possa reduzir o tamanho dos conjuntos de dados, o TOAST (The Oversized Attribute Storage Technique) não é o seu mecanismo tradicional de compactação de dados. Para entender o que é TOAST, temos que começar falando sobre
As unidades de armazenamento do Postgres são chamadas de páginas e têm tamanho fixo (8 KB por padrão). Ter um tamanho de página fixo dá ao Postgres muitas vantagens, nomeadamente a sua simplicidade, eficiência e consistência de gestão de dados, mas tem uma desvantagem: alguns valores de dados podem não caber nessa página.
É aqui que entra o TOAST. TOAST refere-se ao mecanismo automático que o PostgreSQL usa para armazenar e gerenciar com eficiência valores no Postgres que não cabem em uma página. Para lidar com esses valores, o Postgres TOAST irá, por padrão, compactá-los usando um algoritmo interno. Se, após a compactação, os valores ainda forem muito grandes, o Postgres irá movê-los para uma tabela separada (chamada tabela TOAST), deixando ponteiros na tabela original.
Como veremos mais adiante neste artigo, você pode modificar essa estratégia como usuário, por exemplo, informando ao Postgres para evitar a compactação de dados em uma coluna específica.
Os tipos de dados que podem ser submetidos ao TOAST são principalmente aqueles de comprimento variável que têm o potencial de exceder os limites de tamanho de uma página PostgreSQL padrão. Por outro lado, tipos de dados de comprimento fixo, como integer
, float
ou timestamp
, não estão sujeitos ao TOAST, pois cabem confortavelmente em uma página.
Alguns exemplos de tipos de dados que podem estar sujeitos ao TOAST são:
json
e jsonb
Sequências text
grandes
varchar
e varchar(n)
(se o comprimento especificado em varchar(n)
for pequeno o suficiente, os valores dessa coluna poderão sempre permanecer abaixo do limite do TOAST.)
bytea
armazenando dados binários
Dados geométricos como path
e polygon
e tipos PostGIS como geometry
ou geography
Compreender o TOAST não está relacionado apenas ao conceito de tamanho de página, mas também a outro conceito de armazenamento do Postgres: tuplas. Tuplas são linhas em uma tabela PostgreSQL. Normalmente, o mecanismo TOAST entra em ação se todos os campos dentro de uma tupla tiverem um tamanho total superior a 2 kB aproximadamente.
Se você está prestando atenção, pode estar se perguntando: “Espere, mas o tamanho da página é de cerca de 8 KB – por que essa sobrecarga?” Isso ocorre porque o PostgreSQL gosta de garantir que pode armazenar múltiplas tuplas em uma única página: se as tuplas forem muito grandes, menos tuplas caberão em cada página, levando a um aumento nas operações de E/S e redução no desempenho.
O Postgres também precisa manter espaço livre para acomodar dados operacionais adicionais: cada página armazena não apenas os dados da tupla, mas também informações adicionais para gerenciar os dados, como identificadores de itens, cabeçalhos e informações de transações.
Portanto, quando o tamanho combinado de todos os campos em uma tupla excede aproximadamente 2 kB (ou o parâmetro limite TOAST, como veremos mais tarde), o PostgreSQL toma medidas para garantir que os dados sejam armazenados de forma eficiente. TOAST lida com isso de duas maneiras principais:
Compressão. O PostgreSQL pode compactar os valores de campos grandes dentro da tupla para reduzir seu tamanho usando um algoritmo de compactação que abordaremos mais adiante neste artigo. Por padrão, se a compactação for suficiente para reduzir o tamanho total da tupla abaixo do limite, os dados permanecerão na tabela principal, embora em formato compactado.
Armazenamento fora de linha. Se a compactação por si só não for eficaz o suficiente para reduzir o tamanho dos valores grandes dos campos, o Postgres os moverá para uma tabela TOAST separada. Este processo é conhecido como armazenamento "fora de linha" porque a tupla original na tabela principal não contém mais os valores grandes dos campos. Em vez disso, ele contém um "ponteiro" ou referência para a localização dos grandes dados na tabela TOAST.
Estamos simplificando um pouco as coisas neste artigo—
pglz
Mencionamos que o TOAST pode compactar valores grandes no PostgreSQL. Mas qual algoritmo de compactação o PostgreSQL está usando e quão eficaz ele é?
O pglz
(PostgreSQL Lempel-Ziv) é o algoritmo de compactação interna padrão usado pelo PostgreSQL especificamente adaptado para o TOAST.
Veja como funciona em termos muito simples:
pglz
tenta evitar dados repetidos. Quando vê dados repetidos, em vez de escrever a mesma coisa novamente, apenas aponta para onde os escreveu antes. Esse “evitar repetição” ajuda a economizar espaço.
À medida que pglz
lê os dados, ele se lembra de alguns dos dados recentes que viu. Essa memória recente é chamada de “janela deslizante”.
À medida que novos dados chegam, pglz
verifica se os viu recentemente (dentro de sua janela deslizante). Se sim, ele grava uma referência curta em vez de repetir os dados.
Se os dados forem novos ou não forem repetidos o suficiente para tornar uma referência mais curta que os dados reais, pglz
apenas os anota como estão.
Quando chega a hora de ler os dados compactados, pglz
usa suas referências para buscar os dados originais. Este processo é bastante direto, pois procura os dados referidos e coloca-os no seu devido lugar.
pglz
não precisa de armazenamento separado para sua memória (a janela deslizante); ele o constrói em movimento durante a compactação e faz o mesmo durante a descompactação.
Esta implementação foi projetada para oferecer um equilíbrio entre eficiência de compactação e velocidade dentro do mecanismo TOAST. Em termos de taxa de compressão, a eficácia do pglz
dependerá em grande parte da natureza dos dados.
Por exemplo, dados altamente repetitivos serão compactados muito melhor do que dados de alta entropia (como dados aleatórios). Você pode ver taxas de compactação na faixa de 25 a 50 por cento, mas esta é uma estimativa muito geral – os resultados variam amplamente com base na natureza exata dos dados.
Por padrão, o PostgreSQL passará pelo mecanismo TOAST de acordo com o procedimento explicado anteriormente (primeiro a compactação e depois o armazenamento fora de linha, se a compactação não for suficiente). Ainda assim, pode haver cenários em que você queira ajustar esse comportamento por coluna. O PostgreSQL permite que você faça isso usando as estratégias TOAST PLAIN
, EXTERNAL
, EXTENDED
e MAIN
.
EXTENDED
: Esta é a estratégia padrão. Isso implica que os dados serão armazenados fora de linha em uma tabela TOAST separada se for muito grande para uma página de tabela normal. Antes de mover os dados para a tabela TOAST, eles serão compactados para economizar espaço.
EXTERNAL
: Esta estratégia diz ao PostgreSQL para armazenar os dados desta coluna fora de linha se os dados forem muito grandes para caber em uma página de tabela normal, e estamos pedindo ao PostgreSQL para não compactar os dados - o valor será apenas movido para o Tabela TOAST como está.
MAIN
: Esta estratégia é um meio termo. Ele tenta manter os dados alinhados na tabela principal por meio de compactação; se os dados forem definitivamente muito grandes, ele os moverá para a tabela TOAST para evitar um erro, mas o PostgreSQL não moverá os dados compactados. Em vez disso, armazenará o valor na tabela TOAST em sua forma original.
PLAIN
: Usar PLAIN
em uma coluna diz ao PostgreSQL para sempre armazenar os dados da coluna em linha na tabela principal, garantindo que não sejam movidos para uma tabela TOAST fora de linha. Leve em consideração que se os dados ultrapassarem o tamanho da página, o INSERT
falhará porque os dados não caberão.
Se quiser inspecionar as estratégias atuais de uma tabela específica, você pode executar o seguinte:
\d+ your_table_name
Você obterá uma saída como esta:
=> \d+ example_table Table "public.example_table" Column | Data Type | Modifiers | Storage | Stats target | Description ---------+------------------+-----------+----------+--------------+------------- bar | varchar(100000) | | extended | |
Se desejar modificar a configuração de armazenamento, você pode fazer isso usando o seguinte comando:
-- Sets EXTENDED as the TOAST strategy for bar_column ALTER TABLE example_blob ALTER COLUMN bar_column SET STORAGE EXTENDED;
Além das estratégias acima, estes dois parâmetros também são importantes para controlar o comportamento do TOAST:
TOAST_TUPLE_THRESHOLD
Este é o parâmetro que define o limite de tamanho para quando as operações TOASTing (compactação e armazenamento fora de linha) são consideradas para tuplas superdimensionadas.
Como mencionamos anteriormente, por padrão, TOAST_TUPLE_THRESHOLD
é definido para aproximadamente 2 kB.
TOAST_COMPRESSION_THRESHOLD
Este é o parâmetro que especifica o tamanho mínimo de um valor antes que o Postgres considere compactá-lo durante o processo TOASTing.
Se um valor ultrapassar esse limite, o PostgreSQL tentará compactá-lo. No entanto, só porque um valor está acima do limite de compactação, isso não significa automaticamente que será compactado: as estratégias TOAST orientarão o PostgreSQL sobre como lidar com os dados com base em se eles foram compactados e em seu tamanho resultante em relação à tupla e limites de página, como veremos na próxima seção.
TOAST_TUPLE_THRESHOLD
é o ponto de gatilho. Quando o tamanho dos campos de dados de uma tupla combinados exceder esse limite, o PostgreSQL avaliará como gerenciá-lo com base na estratégia TOAST definida para suas colunas, considerando compactação e armazenamento fora de linha. As ações exatas tomadas também dependerão se os dados da coluna ultrapassam TOAST_COMPRESSION_THRESHOLD
:
EXTENDED
(estratégia padrão): Se o tamanho de uma tupla exceder TOAST_TUPLE_THRESHOLD
, o PostgreSQL tentará primeiro compactar as colunas superdimensionadas se elas também excederem TOAST_COMPRESSION_THRESHOLD
. Se a compactação reduzir o tamanho da tupla abaixo do limite, ela permanecerá na tabela principal. Caso contrário, os dados serão movidos para uma tabela TOAST fora de linha e a tabela principal conterá ponteiros para esses dados externos.
MAIN
: Se o tamanho da tupla ultrapassar TOAST_TUPLE_THRESHOLD
, o PostgreSQL tentará compactar as colunas superdimensionadas (desde que ultrapassem TOAST_COMPRESSION_THRESHOLD
). Se a compactação permitir que a tupla caiba na tupla da tabela principal, ela permanecerá lá. Caso contrário, os dados serão movidos para a tabela TOAST em seu formato descompactado.
EXTERNAL
: O PostgreSQL ignora a compactação, independentemente do TOAST_COMPRESSION_THRESHOLD
. Se o tamanho da tupla for superior a TOAST_TUPLE_THRESHOLD
, as colunas superdimensionadas serão armazenadas fora de linha na tabela TOAST.
PLAIN
: Os dados são sempre armazenados na tabela principal. Se o tamanho de uma tupla exceder o tamanho da página (devido a colunas muito grandes), um erro será gerado.
Estratégia | Compactar se tupla > TOAST_COMPRESSION_THRESHOLD | Armazenar fora de linha se tupla > TOAST_TUPLE_THRESHOLD | Descrição |
---|---|---|---|
ESTENDIDO | Sim | Sim | Estratégia padrão. Compacta primeiro e depois verifica se o armazenamento fora de linha é necessário. |
PRINCIPAL | Sim | Somente na forma descompactada | Comprime primeiro e, se ainda estiver superdimensionado, passa para a tabela TOAST sem compactação. |
EXTERNO | Não | Sim | Sempre passa para TOAST se for superdimensionado, sem compressão. |
SIMPLES | Não | Não | Os dados sempre ficam na tabela principal. Se uma tupla exceder o tamanho da página, ocorrerá um erro. |
Até agora, você provavelmente já entenderá por que o TOAST não é o mecanismo de compactação de dados que você gostaria de ter no PostgreSQL. As aplicações modernas implicam grandes volumes de dados consumidos diariamente, o que significa que os bancos de dados (sobre)crescem rapidamente.
Esse problema não era tão proeminente quando nosso querido Postgres foi criado décadas atrás, mas os desenvolvedores de hoje precisam de soluções de compactação para reduzir o espaço de armazenamento de seus conjuntos de dados.
Embora o TOAST incorpore a compactação como uma de suas técnicas, é crucial entender que sua função principal não é servir como mecanismo de compactação de banco de dados no sentido tradicional. TOAST é principalmente uma solução para um problema: gerenciar grandes valores dentro dos limites estruturais de uma página Postgres.
Embora essa abordagem possa levar a alguma economia de espaço de armazenamento devido à compactação de grandes valores específicos, seu objetivo principal não é otimizar o espaço de armazenamento em todos os aspectos.
Por exemplo, se você tiver um banco de dados de 5 TB composto de pequenas tuplas, o TOAST não ajudará você a transformar esses 5 TB em 1 TB. Embora existam parâmetros no TOAST que podem ser ajustados, isso não transformará o TOAST em uma solução generalizada de economia de armazenamento.
E há outros problemas inerentes ao uso do TOAST como mecanismo de compactação tradicional no PostgreSQL, por exemplo:
Acessar dados TOASTed pode adicionar sobrecarga, especialmente quando os dados são armazenados fora de linha. Isso se torna mais evidente quando muitos textos grandes ou outros tipos de dados compatíveis com TOAST são acessados com frequência.
O TOAST carece de um mecanismo fácil de usar e de alto nível para ditar políticas de compactação. Ele não foi desenvolvido para otimizar os custos de armazenamento ou facilitar o gerenciamento do armazenamento.
A compressão do TOAST não foi projetada para fornecer taxas de compressão especialmente altas. Ele usa apenas um algoritmo ( pglz
) com taxas de compactação variando normalmente de 25 a 50 por cento.
Ao adicionar uma política de compactação às suas tabelas grandes,
Ao definir uma política de compactação baseada em tempo, você indica quando os dados devem ser compactados. Por exemplo, você pode optar por compactar dados com mais de sete (7) dias automaticamente:
-- Compress data older than 7 days SELECT add_compression_policy('my_hypertable', INTERVAL '7 days');
Através desta política de compressão, o Timescale transformará a tabela
Compressão Gorilla para carros alegóricos
Delta-de-delta +
Compactação de dicionário de linha inteira para colunas com alguns valores repetidos (+ compactação LZ na parte superior)
Compressão de array baseada em LZ para todos os outros tipos
Este design de compactação colunar oferece uma solução eficiente e escalonável para o problema de grandes conjuntos de dados no PostgreSQL. Ele permite que você use menos armazenamento para armazenar mais dados sem prejudicar o desempenho da consulta (melhora). E nas versões mais recentes do TimescaleDB, você também pode INSERT
, DELETE
e UPDATE
diretamente sobre dados compactados.
Esperamos que este artigo tenha ajudado você a entender que, embora o TOAST seja um mecanismo bem pensado para gerenciar grandes valores em uma página PostgreSQL, ele não é eficaz para otimizar o uso do armazenamento de banco de dados no âmbito dos aplicativos modernos.
Se você está procurando uma compactação de dados eficaz que possa impulsionar sua economia de armazenamento, experimente o Timescale. Você pode experimentar nossa plataforma em nuvem que impulsiona o PostgreSQL a novos patamares de desempenho, tornando-o mais rápido e poderoso.
Escrito por Carlota Soto .