Quelle est la surcharge pour varchar (n)?

15

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

La mémoire requise 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 varchar(255)champ. 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 de 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 document de la même manière que moi, mais ici, quelqu'un déclare que la surcharge est toujours de 4 octets ici ?

appuyez sur la touche
la source

Réponses:

19

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

D'une part, la taille sur le disque (dans n'importe quelle table , même lorsqu'elle n'est pas réellement stockée sur le disque) peut être différente de la taille en mémoire . Sur le disque, la surcharge pour les varcharvaleurs courtes jusqu'à 126 octets est réduite à 1 octet comme indiqué dans le manuel. Mais la surcharge en mémoire est toujours de 4 octets (une fois les valeurs individuelles extraites).

La même chose est vrai pour text, varchar, varchar(n)ouchar(n) - sauf que char(n)est complétée par des blancs à ncaractères et vous ne voulez pas l' utiliser normalement. Sa taille effective peut toujours varier dans les codages multi-octets car ndénote un maximum de caractères, pas d'octets:

les chaînes peuvent contenir jusqu'à des ncaractères (et non des octets).

Tous les utilisent en varlenainterne.
"char"(avec des guillemets doubles) est une créature différente et occupe toujours un seul octet.
Les littéraux de chaîne non typés ( 'foo') ont une surcharge d'un seul 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 la RAM (donc 1 octet contre 4 octets de surcharge).
  • La chaîne de 140 octets «123 ...» occupe 144 octets sur le disque et dans la RAM (donc toujours 4 octets de surcharge).
  • Le stockage de integern'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 de tuple (plus 4 octets supplémentaires par tuple pour le pointeur d'élément dans l'en-tête de page).
  • Et dernier point mais non des moindres: le surdébit du petit varcharn'est toujours que de 1 octet alors qu'il n'a pas été extrait de la ligne - comme on peut le voir sur la taille de la ligne. (C'est pourquoi il est parfois un peu plus rapide de sélectionner des lignes entières.)

En relation:

Erwin Brandstetter
la source
1
Cette surcharge de 1 octet est-elle toujours de 1 octet dans l'index?
dvtan
1
@dtgq: Un index stocke des données comme une table, alors oui.
Erwin Brandstetter