web-dev-qa-db-fra.com

Quelle est la surcharge pour varchar (n)?

Je voulais demander la signification de ce fragment de Postgres doc concernant varchar(n) type:

Le stockage requis pour une chaîne courte (jusqu'à 126 octets) est de 1 octet plus la chaîne réelle, qui inclut le remplissage d'espace dans le cas des caractères. Les chaînes plus longues ont 4 octets de surcharge au lieu de 1.

Supposons que j'ai un champ varchar(255). Et maintenant, les déclarations suivantes:

  • Si ce champ contient une chaîne de 10 octets, la surcharge est de 1 octet. La chaîne utilisera donc 11 octets.
  • Si le champ contient une chaîne utilisant 140 octets, la surcharge est de 4 octets. La chaîne utilisera donc 144 octets.

Ces déclarations ci-dessus sont-elles vraies? Ici quelqu'un comprend le doc de la même manière que moi mais ici quelqu'un déclare que la surcharge est toujours de 4 octets ici ?

15
keypress

Sans surprise, le manuel est juste. Mais il y a plus que cela.

D'une part, la taille sur le disque (dans n'importe quel tableau, même lorsqu'il n'est pas réellement stockées sur le disque) peuvent être différentes de la taille en mémoire. Sur le disque, la surcharge pour les valeurs courtes varchar jusqu'à 126 octets est réduite à un 1 octet comme indiqué dans le manuel. Mais la surcharge en mémoire est toujours de 4 octets (une fois les valeurs individuelles extraites).

Il en va de même pour text, varchar, varchar(n) ou char(n) - sauf que char(n) est rempli de caractères n et vous ne voulez normalement pas l'utiliser. Sa taille effective peut toujours varier dans les codages multi-octets car n désigne un maximum de caractères, pas d'octets:

chaînes jusqu'à n caractères (pas d'octets) de longueur.

Tous utilisent varlena en interne.
"char" (Avec des guillemets doubles) est une créature différente et occupe toujours un seul octet.
littéraux de chaîne non typés ('foo') Ont une surcharge de 1 octet. À ne pas confondre avec les valeurs tapées!

Testez avec 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

Comme vous pouvez le voir:

  • La chaîne de 3 octets 'foo' occupe 4 octets sur le disque et 7 octets dans RAM (donc 1 octet contre 4 octets de surcharge).
  • La chaîne de 140 octets '123 ...' occupe 144 octets sur le disque et en RAM (donc toujours 4 octets de surcharge).
  • Le stockage de integer n'a pas de surcharge (mais il a des exigences d'alignement qui peuvent imposer un remplissage).
  • La ligne a une surcharge supplémentaire de 24 octets pour l'en-tête Tuple (plus 4 octets supplémentaires par Tuple pour le pointeur d'élément dans l'en-tête de page).
  • Et enfin et surtout: le surdébit du petit varchar n'est toujours que de 1 octet alors qu'il n'a pas été extrait de la ligne - comme le montre la taille de la ligne. (C'est pourquoi il est parfois un peu plus rapide de sélectionner des lignes entières.)

En relation:

19
Erwin Brandstetter