Índice de rendimiento para CHAR vs VARCHAR (Postgres)

16

En esta respuesta ( /programming/517579/strings-as-primary-keys-in-sql-database ) un solo comentario me llamó la atención:

También tenga en cuenta que a menudo hay una gran diferencia entre un CHAR y un VARCHAR al hacer comparaciones de índices

¿Esto aplica / todavía aplica para Postgres?

Encontré páginas en Oracle que afirman que CHARes más o menos un alias VARCHARy, por lo tanto, el rendimiento del índice es el mismo, pero no encontré nada definitivo en Postgres.

LetMeSOThat4U
fuente

Respuestas:

24

CHARy VARCHARse implementan exactamente igual en Postgres (y Oracle). No hay diferencia en la velocidad cuando se usan esos tipos de datos.

Sin embargo, hay una diferencia que puede marcar una diferencia en el rendimiento: una charcolumna siempre se rellena a la longitud definida. Entonces, si define una columna como char(100)y una comovarchar(100) pero solo almacena 10 caracteres en cada una, la char(100)columna usa 100 caracteres para cada valor (los 10 caracteres que almacenó, más 90 espacios), mientras que la varcharcolumna solo almacena 10 caracteres.

Comparar 100 caracteres con 100 caracteres será más lento que comparar 10 caracteres con 10 caracteres, aunque dudo que pueda medir esta diferencia en una consulta SQL.

Si declara ambos con la longitud de 10 caracteres y siempre almacena exactamente 10 caracteres en ellos, entonces no hay absolutamente ninguna diferencia (esto es cierto para Oracle y Postgres)

Entonces, la única diferencia es el relleno que se hace para el chartipo de datos.


También tenga en cuenta que a menudo hay una gran diferencia entre un CHAR y un VARCHAR al hacer comparaciones de índices

La cita anterior solo es cierta si (y solo si) la charcolumna se define demasiado amplia (es decir, está desperdiciando espacio debido al relleno). Si la longitud de la charcolumna siempre se usa completamente (por lo que no se produce relleno), entonces la cita anterior es incorrecta (al menos para Postgres y Oracle)


Desde mi punto de vista, el chartipo de datos realmente no tiene ningún uso de palabras reales. Simplemente use varchar(o texten Postgres) y olvide que charexiste.

un caballo sin nombre
fuente
2
Comparar 100 caracteres con 100 caracteres será más lento que comparar 10 caracteres con 10 caracteres, aunque dudo que pueda medir esta diferencia en una consulta SQL. - Dependiendo de lo que haga la consulta además de ordenar, la diferencia puede ser enorme. Es por eso que Postgres 9.5 tiene una nueva característica de "claves abreviadas": pgeoghegan.blogspot.de/2015/01/…
chirlu
6

Estoy de acuerdo con todo lo dicho por a_horse_with_no_name, y generalmente estoy de acuerdo con el comentario de Erwin:

No, char es inferior (y anticuado). text y varchar realizan (casi) lo mismo.

Metadatos

Con una pequeña excepción, el único momento que uso char()es cuando quiero que los metadatos digan que DEBE tener caracteres x. Aunque sé que char()solo se queja si la entrada está por encima del límite, con frecuencia protegeré contra los bajos fondos en una CHECKrestricción. Por ejemplo,

CREATE TABLE foo (
  x char(10) CHECK ( length(x) = 10 )
);
INSERT INTO foo VALUES (repeat('x', 9));

Hago esto por algunas razones,

  1. char(x)a veces se infiere con los cargadores de esquemas como una columna de ancho fijo. Esto puede marcar la diferencia en un lenguaje optimizado para cadenas de ancho fijo.
  2. Establece una convención que tiene sentido y se aplica fácilmente. Puedo escribir un cargador de esquemas en un lenguaje para generar código a partir de esta convención.

Necesito un ejemplo de dónde puedo hacer esto,

  1. Abreviaturas de estado de dos letras, aunque debido a que esta lista se puede enumerar, normalmente lo haré con un ENUM .
  2. Números de identificación del vehículo
  3. Números de modelo (de tamaño fijo)

En errores

Tenga en cuenta que algunas personas pueden sentirse incómodas con la incongruencia de los mensajes de error en ambos lados del límite, pero no me molesta

test=# INSERT INTO foo VALUES (repeat('x', 9));
ERROR:  new row for relation "foo" violates check constraint "foo_x_check"
DETAIL:  Failing row contains (xxxxxxxxx ).
test=# INSERT INTO foo VALUES (repeat('x', 11));
ERROR:  value too long for type character(10)

Contrastar con varchar

Además, creo que la sugerencia anterior encaja muy bien con una convención de uso casi siempretext . Usted pregunta por eso varchar(n)también. Yo nunca uso eso . Al menos, no recuerdo la última vez que lo usé varchar(n).

  • Si una especificación tiene un campo de ancho estático en el que confío, utilizo char(n) ,
  • De lo contrario, uso textcual es efectivamente varchar(sin límite)

Si encontrara una especificación que tuviera claves de texto de longitud variable que fueran significativas y confiara en tener una longitud máxima constante, usaría varchar(n) también la . Sin embargo, no puedo pensar en nada que se ajuste a ese criterio.

Notas adicionales

Preguntas y respuestas relacionadas:

Evan Carroll
fuente
1

Postgresql

sales_reporting_db=# create table x (y char(2));
CREATE TABLE
sales_reporting_db=# insert into x values ('Y');
INSERT 0 1
sales_reporting_db=# select '*' || y || '*' from x;
 ?column? 
----------
 *Y*

Oráculo

SQL> create table x ( y char(2));

Table created.

SQL> insert into x values ('Y');

1 row created.

SQL> select '*' || y || '*' from x;

'*'|
----
*Y *

Postgresql no rellenó con espacios.

usuario939857
fuente
Eso es solo una ilusión óptica en Postgres. ProbarSELECT pg_column_size(y) FROM x;
dezso
-2

Encontré esto más útil, y una explicación rápida de 3 líneas:

De CHAR (n) Vs VARCHAR (N) Vs Texto en Postgres

  • Si desea almacenar texto con una longitud desconocida, use el TEXT tipo de datos.
  • Si desea almacenar texto con una longitud desconocida, pero conoce la longitud máxima, use VARCHAR(n) .
  • Si desea almacenar un texto con una longitud exacta conocida, use CHAR(N).
Luis
fuente