¿Cuál es la sobrecarga para varchar (n)?

15

Quería preguntar el significado de este fragmento del documento de Postgres con respecto al varchar(n)tipo:

El requisito de almacenamiento para una cadena corta (hasta 126 bytes) es de 1 byte más la cadena real, que incluye el relleno de espacio en el caso de caracteres. Las cadenas más largas tienen 4 bytes de sobrecarga en lugar de 1.

Asumamos que tengo un varchar(255)campo. Y ahora, las siguientes declaraciones:

  • Si este campo contiene una cadena de 10 bytes, la sobrecarga es de 1 byte. Entonces la cadena usará 11 bytes.
  • Si el campo contiene una cadena que usa 140 bytes, la sobrecarga es de 4 bytes. Entonces la cadena usará 144 bytes.

¿Son ciertas esas afirmaciones anteriores? ¿Aquí alguien entiende el documento de la misma manera que yo pero aquí alguien dice que la sobrecarga es siempre de 4 bytes aquí ?

pulsación de tecla
fuente

Respuestas:

19

Como era de esperar, el manual es correcto. Pero hay más que eso.

Por un lado, el tamaño en el disco (en cualquier tabla , incluso cuando no está realmente almacenado en el disco) puede ser diferente del tamaño en la memoria . En el disco, la sobrecarga para varcharvalores cortos de hasta 126 bytes se reduce a 1 byte como se indica en el manual. Pero la sobrecarga en la memoria siempre es de 4 bytes (una vez que se extraen los valores individuales).

Lo mismo es cierto para text, varchar, varchar(n)ochar(n) - excepto que char(n)es rellenada con blancos a nlos personajes y que normalmente no se desea utilizarlo. Su tamaño efectivo aún puede variar en codificaciones de varios bytes porque ndenota un máximo de caracteres, no bytes:

cadenas de hasta ncaracteres (no bytes) de longitud.

Todos ellos usan varlenainternamente.
"char"(con comillas dobles) es una criatura diferente y siempre ocupa un solo byte.
Los literales de cadena sin tipo ( 'foo') tienen una sobrecarga de un solo byte. ¡No debe confundirse con los valores escritos!

Prueba con 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 puedes ver:

  • La cadena 'foo' de 3 bytes ocupa 4 bytes en el disco y 7 bytes en la RAM (1 byte frente a 4 bytes de sobrecarga).
  • La cadena de 140 bytes '123 ...' ocupa 144 bytes tanto en el disco como en la RAM (siempre 4 bytes de sobrecarga).
  • El almacenamiento integerno tiene gastos generales (pero tiene requisitos de alineación que pueden imponer relleno).
  • La fila tiene una sobrecarga adicional de 24 bytes para el encabezado de la tupla (más 4 bytes adicionales por tupla para el puntero del elemento en el encabezado de la página).
  • Y por último, pero no menos importante: la sobrecarga de la pequeña varcharsigue siendo de solo 1 byte mientras no se ha extraído de la fila, como se puede ver en el tamaño de la fila. (Es por eso que a veces es un poco más rápido seleccionar filas enteras).

Relacionado:

Erwin Brandstetter
fuente
1
¿Esa sobrecarga de 1 byte sigue siendo 1 byte en el índice?
dvtan
1
@dtgq: un índice almacena datos como una tabla, así que sí.
Erwin Brandstetter