50.2. TOAST

Esta seção fornece uma visão geral do TOAST (A técnica de armazenamento de atributo de tamanho grande).

Uma vez que o PostgreSQL utiliza um tamanho de página fixo (geralmente 8Kb), e não permite as tuplas se estenderem por várias páginas, não é possível armazenar valores de campo muito grandes diretamente. Antes da versão 7.1 do PostgreSQL, havia um limite rígido de apenas uma página para a quantidade total de dados que podia ser colocado em uma linha da tabela. Na versão 7.1, e posteriores, este limite é superado permitindo os valores dos campos serem comprimidos e/ou divididos em várias linhas físicas. Isto acontece de forma transparente para o usuário, causando apenas um pequeno impacto para a maior parte do código do servidor. Esta técnica é afetuosamente chamada de TOAST (ou "a melhor coisa desde o pão em fatias").

Apenas certos tipos de dado suportam TOAST — não é necessário impor sobrecarga em tipos de dado que não podem produzir valores de campo grandes. Para suportar o TOAST, o tipo de dado deve possuir uma representação de comprimento variável (varlena), na qual a primeira palavra de 32 bits de qualquer valor armazenado contém o comprimento total do valor em bytes (incluindo a si próprio). O TOAST não restringe o restante da representação. Todas as funções no nível-C com suporte a tipo de dado fatiável devem tomar o cuidado de tratar os valores de entrada na forma de TOAST (Geralmente isto é feito chamando PG_DETOAST_DATUM antes de fazer qualquer coisa com o valor de entrada; mas em alguns casos é possível uma abordagem mais eficiente).

TOAST se apodera dos dois bits de mais alta ordem da palavra de comprimento varlena, limitando, portanto, o tamanho lógico de qualquer valor de um tipo de dado fatiável a 1Gb (230 - 1 bytes). Quando os dois bits são iguais a zero, o valor é um valor comum não fatiado do tipo de dado. Um desses bits, se estiver definido, indica que o valor foi comprimido devendo ser descomprimido antes de ser utilizado. O outro bit, se estiver definido, indica que o valor foi armazenado fora-de-linha. Neste caso, o restante do valor é apenas um ponteiro e os dados corretos devem ser encontrados em outro lugar. Quando os dois bits estão definidos, os dados fora-de-linha também estão comprimidos. Em cada caso o comprimento nos bits de mais baixa ordem da palavra varlena indica o tamanho real do dado, e não o tamanho do valor lógico que seria obtido pela descompressão ou busca dos dados fora-de-linha.

Quando alguma coluna da tabela é fatiável, a tabela possui uma tabela TOAST associada, cujo OID é armazenado na entrada pg_class.reltoastrelid da tabela. Os valores fatiados fora-de-linha são mantidos na tabela TOAST, conforme descrito em mais detalhes abaixo.

A técnica de compressão utilizada é um membro bem simples e bem rápido da família de técnicas de compressão LZ. Para obter detalhes deve ser visto o arquivo src/backend/utils/adt/pg_lzcompress.c.

Os valores fora-de-linha são divididos (após a compressão, se esta for aplicada) em pedaços de no máximo TOAST_MAX_CHUNK_SIZE bytes (este valor é um pouco menor que BLCKSZ/4, ou cerca de 2000 bytes por padrão). Cada pedaço é armazenado como uma linha separada na tabela TOAST para a tabela possuidora. Toda tabela TOAST possui as colunas chunk_id (OID identificador de um determinado valor fatiado), chunk_seq (número de seqüência do pedaço dentro de seu valor) e chunk_data (os dados reais do pedaço). Um índice único englobando chunk_id e chunk_seq permite a busca rápida dos valores. O dado ponteiro que representa o valor fora-de-linha fatiado necessita, portanto, armazenar o OID da tabela TOAST onde é feita a procura, e o OID do valor específico (seu chunk_id). Por conveniência, o dado ponteiro também armazena o tamanho do dado lógico (comprimento original do dado não comprimido), e o tamanho real armazenado (diferente, caso tenha sido aplicada compressão). Incluindo a palavra de cabeçalho varlena, o tamanho total do dado ponteiro para TOAST é portanto de 20 bytes, a despeito do tamanho real do valor representado.

O código TOAST é disparado apenas quando um valor de linha a ser armazenado na tabela é maior que BLCKSZ/4 bytes (normalmente 2Kb). O código TOAST comprime e/ou move os valores de campo para fora-de-linha até que o valor da linha se torne menor BLCKSZ/4 bytes, ou que não possa mais obter ganho. Durante a operação de atualização, os valores não alterados dos campos normalmente são preservados na forma em que estão; portanto, a atualização de uma linha com valores fora-de-linha não incorre em custos de TOAST, se nenhum dos valores fora-de-linha for alterado.

O código TOAST reconhece quatro estratégias diferentes para armazenar colunas fatiáveis:

Cada tipo de dado fatiável especifica a estratégia padrão para as colunas deste tipo de dado, mas a estratégia para uma determinada coluna de uma tabela pode ser alterada pelo comando ALTER TABLE SET STORAGE.

Este esquema possui várias vantagens quando comparado com uma abordagem mais direta, como a que permite os valores de linha se estenderem por várias páginas. Assumindo que os comandos geralmente são qualificados por comparações com valores chave relativamente pequenos, a maior parte do trabalho do executor é feito utilizando a entrada principal da linha. Os valores grandes dos atributos fatiados serão trazidos (se forem selecionados), somente na hora em que o conjunto contendo os resultados for enviado para o cliente. Portanto, a tabela principal é muito menor, cabendo uma quantidade maior de suas linhas no cache de buffers compartilhados do que caberia no caso de não haver o armazenamento fora-de-linha. Os conjuntos de classificação também encolhem, e a classificação será feita inteiramente em memória com mais freqüência. Um pequeno teste mostrou que uma tabela contendo páginas HTML típicas, e suas respectivas URLs, foi armazenada na metade do seu tamanho bruto incluindo a tabela TOAST, e que a tabela principal continha apenas 10% de todos os dados (As URLs e algumas páginas HTML pequenas). Não houve diferença no tempo de execução quando comparada com a tabela não fatiada, onde todas as páginas HTML foram cortadas para caber em 7Kb.

SourceForge.net Logo CSS válido!