PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Calculando e economizando espaço no PostgreSQL

"Coluna Tetris"


Na verdade, você pode fazer algo , mas isso precisa de uma compreensão mais profunda. A palavra-chave é preenchimento de alinhamento . Cada tipo de dados tem requisitos de alinhamento específicos.

Você pode minimizar o espaço perdido no preenchimento entre colunas ordenando-os favoravelmente. O exemplo (extremo) a seguir desperdiçaria muito espaço em disco físico:
CREATE TABLE t (
    e int2    -- 6 bytes of padding after int2
  , a int8
  , f int2    -- 6 bytes of padding after int2
  , b int8
  , g int2    -- 6 bytes of padding after int2
  , c int8
  , h int2    -- 6 bytes of padding after int2
  , d int8)

Para salvar 24 bytes por linha, use em vez disso:
CREATE TABLE t (
    a int8
  , b int8
  , c int8
  , d int8
  , e int2
  , f int2
  , g int2
  , h int2)   -- 4 int2 occupy 8 byte (MAXALIGN), no padding at the end

db<>mexa aqui
antigo sqlfiddle

Como regra geral, se você colocar as colunas de 8 bytes primeiro, depois as colunas de 4 bytes, 2 bytes e 1 byte por último, não há como errar.

boolean , uuid (!) e alguns outros tipos não precisam de preenchimento de alinhamento. text , varchar e outros tipos de "varlena" (comprimento variável) nominalmente requerem alinhamento "int" (4 bytes na maioria das máquinas). Mas não observei nenhum preenchimento de alinhamento no formato de disco (ao contrário da RAM). Eventualmente, encontrei a explicação em uma nota no código-fonte:

Observe também que permitimos que o alinhamento nominal seja violado ao armazenar varlenas "empacotadas"; o mecanismo TOAST cuida de esconder isso da maioria dos códigos.

Portanto, o alinhamento "int" só é aplicado quando o datum (possivelmente compactado) incluindo um único byte de comprimento inicial excede 127 bytes. Em seguida, o armazenamento varlena alterna para quatro bytes iniciais e requer alinhamento "int".

Normalmente, você pode salvar alguns bytes por linha, na melhor das hipóteses, jogando "column tetris" . Nada disso é necessário na maioria dos casos. Mas com bilhões de linhas pode significar alguns gigabytes facilmente.

Você pode testar o tamanho real da coluna/linha com a função pg_column_size() .
Alguns tipos ocupam mais espaço na RAM do que no disco (formato compactado ou "empacotado"). Você pode obter resultados maiores para constantes (formato RAM) do que para colunas de tabela ao testar o mesmo valor (ou linha de valores versus linha da tabela) com pg_column_size() .

Finalmente, alguns tipos podem ser compactados ou "torrados" (armazenados fora de linha) ou ambos.

Custo extra por tupla (linha)


4 bytes por linha para o identificador de item - não sujeito às considerações acima.
E pelo menos 24 bytes (23 + preenchimento) para o cabeçalho da tupla. O manual sobre layout de página de banco de dados:

Há um cabeçalho de tamanho fixo (ocupando 23 bytes na maioria das máquinas), seguido por um bitmap nulo opcional, um campo opcional de ID de objeto e os dados do usuário.

Para o preenchimento entre os dados do cabeçalho e do usuário, você precisa saber MAXALIGN em seu servidor - normalmente 8 bytes em um sistema operacional de 64 bits (ou 4 bytes em um sistema operacional de 32 bits). Se você não tiver certeza, confira pg_controldata .

Execute o seguinte em seu diretório binário do Postgres para obter uma resposta definitiva:
./pg_controldata /path/to/my/dbcluster

O manual:

Os dados reais do usuário (colunas da linha) começam no deslocamento indicado por t_hoff , que deve ser sempre um múltiplo de MAXALIGN distância da plataforma.

Portanto, você normalmente obtém o armazenamento ideal empacotando dados em múltiplos de 8 bytes.

Não há nada a ganhar no exemplo que você postou . Já está bem embalado. 2 bytes de preenchimento após o último int2 , 4 bytes no final. Você poderia consolidar o preenchimento para 6 bytes no final, o que não mudaria nada.

Custo extra por página de dados


O tamanho da página de dados geralmente é de 8 KB. Alguma sobrecarga / inchaço neste nível também:Restos não grandes o suficiente para caber em outra tupla e, mais importante, linhas mortas ou uma porcentagem reservada com o FILLFACTOR contexto.

Há alguns outros fatores para o tamanho do disco a serem levados em consideração:
  • Quantos registros posso armazenar em 5 MB de PostgreSQL no Heroku?
  • Não usar NULL no PostgreSQL ainda usa um bitmap NULL no cabeçalho?
  • Configurando o PostgreSQL para desempenho de leitura

Tipos de matriz?


Com uma matriz digite como você estava avaliando, você adicionaria 24 bytes de sobrecarga para o tipo. Além disso, os elementos da matriz ocupam espaço como de costume. Nada a ganhar lá.