Qual é a sobrecarga para varchar (n)?

15

Eu queria pedir o significado desse fragmento do doc do Postgres em relação ao varchar(n)tipo:

O requisito de armazenamento para uma cadeia curta (até 126 bytes) é de 1 byte mais a cadeia real, que inclui o preenchimento de espaço no caso de caractere. Seqüências mais longas têm 4 bytes de sobrecarga em vez de 1.

Vamos supor que eu tenho um varchar(255)campo. E agora, as seguintes declarações:

  • Se esse campo contiver uma sequência de 10 bytes, a sobrecarga será de 1 byte. Portanto, a string usará 11 bytes.
  • Se o campo contiver uma string usando 140 bytes, a sobrecarga será de 4 bytes. Portanto, a string usará 144 bytes.

Essas afirmações acima são verdadeiras? Aqui alguém entende o documento da mesma maneira que eu, mas aqui alguém afirma que a sobrecarga é sempre de 4 bytes aqui ?

pressione o botão
fonte

Respostas:

19

Sem surpresa, o manual está certo. Mas há mais do que isso.

Por um lado, o tamanho do disco (em qualquer tabela , mesmo quando não está realmente armazenado no disco) pode ser diferente do tamanho da memória . No disco, a sobrecarga para varcharvalores curtos de até 126 bytes é reduzida para 1 byte, conforme indicado no manual. Mas a sobrecarga na memória é sempre de 4 bytes (depois que os valores individuais são extraídos).

O mesmo é verdadeiro para text, varchar, varchar(n)ouchar(n) - exceto que char(n)é de preenchimento em branco para ncaracteres e você normalmente não quer usá-lo. Seu tamanho efetivo ainda pode variar nas codificações de vários bytes, porque nindica um máximo de caracteres, não bytes:

seqüências de ncaracteres até caracteres (não bytes) de comprimento.

Todos eles usam varlenainternamente.
"char"(com aspas duplas) é uma criatura diferente e ocupa sempre um único byte.
Os literais de seqüência de caracteres sem tipo ( 'foo') têm uma única sobrecarga de bytes. Não deve ser confundido com valores digitados!

Teste com pg_column_size().

CREATE TEMP TABLE t (id int, v_small varchar, v_big varchar);
INSERT INTO t VALUES (1, 'foo', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');

SELECT pg_column_size(id)        AS id
     , pg_column_size(v_small)   AS v_small
     , pg_column_size(v_big)     AS v_big
     , pg_column_size(t)         AS t
FROM   t
UNION ALL  -- 2nd row measuring values in RAM
SELECT pg_column_size(1)
     , pg_column_size('foo'::varchar)
     , pg_column_size('12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'::varchar)
     , pg_column_size(ROW(1, 'foo'::varchar, '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'::varchar));

 id | v_small | v_big |  t
----+---------+-------+-----
  4 |       4 |   144 | 176
  4 |       7 |   144 | 176

Como você pode ver:

  • A string de 3 bytes 'foo' ocupa 4 bytes no disco e 7 bytes na RAM (portanto, 1 byte vs. 4 bytes de sobrecarga).
  • A cadeia de caracteres de 140 bytes '123 ...' ocupa 144 bytes no disco e na RAM (portanto, sempre 4 bytes de sobrecarga).
  • O armazenamento de integernão possui sobrecarga (mas possui requisitos de alinhamento que podem impor preenchimento).
  • A linha possui uma sobrecarga adicional de 24 bytes para o cabeçalho da tupla (mais 4 bytes adicionais por tupla para o ponteiro do item no cabeçalho da página).
  • E por último, mas não menos importante: a sobrecarga do pequeno varcharainda tem apenas 1 byte, enquanto não foi extraída da linha - como pode ser visto no tamanho da linha. É por isso que às vezes é um pouco mais rápido selecionar linhas inteiras.

Palavras-chave:

Erwin Brandstetter
fonte
1
Essa sobrecarga de 1 byte ainda está 1 byte no índice?
dvtan
1
@dtgq: Um índice armazena dados como uma tabela, então sim.
Erwin Brandstetter