PostgreSQL: diferencia entre texto y varchar (variación de caracteres)

620

¿Cuál es la diferencia entre el texttipo de datos y los tipos de datos character varying( varchar)?

De acuerdo a la documentación

Si se usa la variación de caracteres sin un especificador de longitud, el tipo acepta cadenas de cualquier tamaño. Este último es una extensión PostgreSQL.

y

Además, PostgreSQL proporciona el tipo de texto, que almacena cadenas de cualquier longitud. Aunque el texto de tipo no está en el estándar SQL, otros sistemas de administración de bases de datos SQL también lo tienen.

Entonces, ¿cuál es la diferencia?

Adam Matan
fuente

Respuestas:

746

No hay diferencia, debajo del capó es todo varlena( matriz de longitud variable ).

Consulte este artículo de Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Un par de puntos destacados:

Para resumir todo esto:

  • char (n): ocupa demasiado espacio cuando se manejan valores más cortos que n(los rellena n) y puede generar errores sutiles debido a la adición de espacios finales, además es problemático cambiar el límite
  • varchar (n): es problemático cambiar el límite en el entorno en vivo (requiere un bloqueo exclusivo mientras se modifica la tabla)
  • varchar - al igual que el texto
  • texto - para mí un ganador - sobre (n) tipos de datos porque carece de sus problemas, y sobre varchar - porque tiene un nombre distinto

El artículo realiza pruebas detalladas para mostrar que el rendimiento de las inserciones y las selecciones para los 4 tipos de datos son similares. También toma una mirada detallada a formas alternativas de restringir la longitud cuando sea necesario. Las restricciones o dominios basados ​​en funciones proporcionan la ventaja de un aumento instantáneo de la restricción de longitud, y sobre la base de que es poco frecuente reducir una restricción de longitud de cadena, depesz concluye que una de ellas suele ser la mejor opción para un límite de longitud.

Frank Heikens
fuente
58
@axiopisty Es un gran artículo. Podrías simplemente decir: "¿Podrías hacer algunos extractos en caso de que el artículo caiga alguna vez?" He tratado de resumir brevemente el contenido / conclusiones del artículo. Espero que esto sea suficiente para calmar sus preocupaciones.
jpmc26
34
@axiopisty, estrictamente hablando, la respuesta inicial era " debajo del capó todo es varlena ", que sin duda es información útil que distingue esta respuesta de una respuesta de solo enlace.
Bruno
24
Una cosa a tener en cuenta con una cadena ilimitada es que abren el potencial de abuso. Si permite que un usuario tenga un apellido de cualquier tamaño, es posible que alguien almacene GRANDES cantidades de información en su campo de apellido. En un artículo sobre el desarrollo de reddit, aconsejan "Poner un límite a todo".
Mark Hildreth
77
@MarkHildreth Buen punto, aunque en general estas restricciones se aplican aún más en una aplicación en estos días, de modo que las reglas (e intentos de violaciones / reintentos) pueden ser manejados sin problemas por la interfaz de usuario. Si alguien todavía quiere hacer este tipo de cosas en la base de datos, podría usar restricciones. Consulte blog.jonanin.com/2013/11/20/postgresql-char-varchar que incluye "un ejemplo de uso de TEXT y restricciones para crear campos con más flexibilidad que VARCHAR".
Ethan
44
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Esto está desactivado, pero se encuentra aquí archive.is/6xhA5 .
MrR
115

Como " conjuntos de caracteres " en los puntos de documentación a cabo, varchar(n), char(n), y textse almacenan de la misma manera. La única diferencia es que se necesitan ciclos adicionales para verificar la longitud, si se da uno, y el espacio y el tiempo adicionales necesarios si se necesita relleno char(n).

Sin embargo, cuando solo necesita almacenar un solo carácter, existe una ligera ventaja de rendimiento al usar el tipo especial "char"(mantenga las comillas dobles, son parte del nombre del tipo). Obtiene un acceso más rápido al campo y no hay gastos generales para almacenar la longitud.

Acabo de hacer una tabla de 1,000,000 "char"elegidos al azar del alfabeto en minúsculas. Una consulta para obtener una distribución de frecuencia ( select count(*), field ... group by field) tarda aproximadamente 650 milisegundos, frente a aproximadamente 760 en los mismos datos utilizando un textcampo.

Jorge
fuente
18
técnicamente las comillas no son parte del nombre del tipo. son necesarios para diferenciarlo de la palabra clave char.
Jasen
31
Técnicamente estás en lo correcto @Jasen ... Que, por supuesto, es el mejor tipo de correcto
JohannesH
tipo de datos "char" no es char?? ¿Es válido actualmente en PostgreSQL 11+? ... Sí: "El tipo "char"(tenga en cuenta las comillas) es diferente de char (1) en que solo usa un byte de almacenamiento. Se usa internamente en los catálogos del sistema como un tipo de enumeración simplista ". , guía / datatype-character .
Peter Krauss
64

ACTUALIZACIÓN DE BANCOS PARA 2016 (pg9.5 +)

Y utilizando puntos de referencia "SQL puro" (sin ningún script externo)

  1. use cualquier string_generator con UTF8

  2. principales puntos de referencia:

    2.1. INSERTAR

    2.2. SELECCIONE comparando y contando


CREATE FUNCTION string_generator(int DEFAULT 20,int DEFAULT 10) RETURNS text AS $f$
  SELECT array_to_string( array_agg(
    substring(md5(random()::text),1,$1)||chr( 9824 + (random()*10)::int )
  ), ' ' ) as s
  FROM generate_series(1, $2) i(x);
$f$ LANGUAGE SQL IMMUTABLE;

Preparar prueba específica (ejemplos)

DROP TABLE IF EXISTS test;
-- CREATE TABLE test ( f varchar(500));
-- CREATE TABLE test ( f text); 
CREATE TABLE test ( f text  CHECK(char_length(f)<=500) );

Realizar una prueba básica:

INSERT INTO test  
   SELECT string_generator(20+(random()*(i%11))::int)
   FROM generate_series(1, 99000) t(i);

Y otras pruebas,

CREATE INDEX q on test (f);

SELECT count(*) FROM (
  SELECT substring(f,1,1) || f FROM test WHERE f<'a0' ORDER BY 1 LIMIT 80000
) t;

... y uso EXPLAIN ANALYZE.

ACTUALIZADO DE NUEVO 2018 (pg10)

pequeña edición para agregar los resultados de 2018 y reforzar las recomendaciones.


Resultados en 2016 y 2018

Mis resultados, después de la media, en muchas máquinas y muchas pruebas: todo lo mismo
(estadísticamente menos desviación estándar que el estándar).

Recomendación

  • Utilice el texttipo de datos,
    evite los antiguos varchar(x)porque a veces no es un estándar, por ejemplo, en las CREATE FUNCTIONcláusulas varchar(x)varchar(y) .

  • límites expresos (¡con el mismo varcharrendimiento!) con CHECKcláusula en el CREATE TABLE
    ej CHECK(char_length(x)<=10).
    Con una pérdida insignificante de rendimiento en INSERT / UPDATE, también puede controlar los rangos y la estructura de la cadena,
    por ejemploCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')

Peter Krauss
fuente
Entonces, ¿no importa que hice todas mis columnas varchar en lugar de texto? No especifiqué la longitud a pesar de que algunos tienen solo 4 - 5 caracteres y ciertamente no 255.
trinchera
1
@ trinchera sí, no importa
FuriousFolder
1
genial, lo rehice para que sea seguro y de todas formas hice todo el texto. Funcionó bien y fue muy fácil agregar millones de registros históricos rápidamente de todos modos.
trinchera
@trench and reader: la única excepción es el tipo de datos más rápido "char", eso no es así char, incluso hoy en día en PostgreSQL 11+. Como dice el carácter guía / tipo de datos "El tipo "char"(tenga en cuenta las comillas) es diferente de char (1) en que solo usa un byte de almacenamiento. Se usa internamente en los catálogos del sistema como un tipo de enumeración simplista ". .
Peter Krauss
3
sigue siendo válido con pg11 en 2019: texto> varchar (n)> text_check> char (n)
Olivier Refalo
37

En el manual de PostgreSQL

No hay diferencia de rendimiento entre estos tres tipos, aparte de un mayor espacio de almacenamiento cuando se usa el tipo de relleno en blanco, y algunos ciclos de CPU adicionales para verificar la longitud cuando se almacena en una columna de longitud limitada. Si bien el carácter (n) tiene ventajas de rendimiento en algunos otros sistemas de bases de datos, no existe tal ventaja en PostgreSQL; de hecho, el carácter (n) suele ser el más lento de los tres debido a sus costos de almacenamiento adicionales. En la mayoría de las situaciones, se debe usar texto o variación de caracteres.

Usualmente uso texto

Referencias: http://www.postgresql.org/docs/current/static/datatype-character.html

un caballo sin nombre
fuente
23

En mi opinión, varchar(n)tiene sus propias ventajas. Sí, todos usan el mismo tipo subyacente y todo eso. Pero, debe señalarse que los índices en PostgreSQL tienen su límite de tamaño de 2712 bytes por fila.

TL; DR: si usa el texttipo de letra sin restricción y tiene índices en estas columnas, es muy posible que alcance este límite para algunas de sus columnas y obtenga un error cuando intente insertar datos, pero con el uso varchar(n)puede evitarlo.

Algunos detalles más: El problema aquí es que PostgreSQL no da ninguna excepción al crear índices para el texttipo o varchar(n)donde nes mayor que 2712. Sin embargo, dará error cuando se intente insertar un registro con un tamaño comprimido mayor que 2712. Significa que puede insertar 100,000 caracteres de cadena que está compuesta por caracteres repetitivos fácilmente porque se comprimirá muy por debajo de 2712, pero es posible que no pueda insertar alguna cadena con 4000 caracteres porque el tamaño comprimido es mayor de 2712 bytes. Si usa varchar(n)where nno es mucho mayor que 2712, estará a salvo de estos errores.

sotn
fuente
Los errores posteriores de postgres al intentar crear indexación para texto solo funcionan para varchar (versión sin la (n)). Sin embargo, solo se probó con postgres incrustados.
Arntg
2
En referencia a: stackoverflow.com/questions/39965834/… que tiene un enlace a PostgreSQL Wiki: wiki.postgresql.org/wiki/… tiene un tamaño máximo de fila de 400 GB, por lo que parece que el límite de 2712 bytes indicado por fila es incorrecto . Tamaño máximo para una base de datos? ilimitado (existen bases de datos de 32 TB) ¿Tamaño máximo para una tabla? ¿32 TB de tamaño máximo para una fila? ¿400 GB de tamaño máximo para un campo? 1 GB ¿Número máximo de filas en una tabla? ilimitado
Bill Worthington
@BillWorthington Sin embargo, los números que publicó no tienen en cuenta la colocación de índices. El byte 2712 trata sobre los límites máximos de btree, es un detalle de implementación para que no pueda encontrarlo en los documentos. Sin embargo, puede probarlo usted mismo o simplemente buscarlo en Google buscando "el tamaño de la fila del índice postgresql excede el máximo de 2712 para el índice", por ejemplo.
sotn
Soy nuevo en PostgeSQL, así que no soy el experto. Estoy trabajando en un proyecto donde quiero almacenar artículos de noticias en una columna en una tabla. Parece que el tipo de columna de texto es lo que usaré. Un tamaño de fila total de 2712 bytes parece demasiado bajo para una base de datos que se supone que está cerca del mismo nivel que Oracle. ¿Le entiendo correctamente que se refiere a indexar un campo de texto grande? No tratando de desafiarte o discutir contigo, solo tratando de entender los límites reales. Si no hay índices involucrados, ¿el límite de fila sería de 400 GB como en la wiki? Gracias por su rápida respuesta.
Bill Worthington
1
@BillWorthington Debe investigar sobre la búsqueda de texto completo. Verifique este enlace, por ejemplo
sotn
18

text y varchar tienen diferentes conversiones de tipo implícito. El mayor impacto que he notado es el manejo de espacios finales. Por ejemplo ...

select ' '::char = ' '::varchar, ' '::char = ' '::text, ' '::varchar = ' '::text

regresa true, false, truey no true, true, truecomo es de esperar.

bpd
fuente
¿Cómo es esto posible? Si a = by a = c, entonces b = c.
Lucas Silva
4

Algo OT: si está utilizando Rails, el formato estándar de las páginas web puede ser diferente. Para los formularios de entrada de datos, los textcuadros son desplazables, pero los cuadros character varying(Rails string) son de una línea. Mostrar vistas son tan largas como sea necesario.

Greg
fuente
2

Una buena explicación de http://www.sqlines.com/postgresql/datatypes/text :

La única diferencia entre TEXT y VARCHAR (n) es que puede limitar la longitud máxima de una columna VARCHAR, por ejemplo, VARCHAR (255) no permite insertar una cadena de más de 255 caracteres.

Tanto TEXT como VARCHAR tienen el límite superior a 1 Gb, y no hay diferencia de rendimiento entre ellos (de acuerdo con la documentación de PostgreSQL).

Chris Halcrow
fuente
-1

character varying(n), varchar(n)- (Ambos lo mismo). el valor se truncará en n caracteres sin generar un error.

character(n), char(n)- (Ambos lo mismo). de longitud fija y se rellenará con espacios en blanco hasta el final de la longitud.

text- Longitud ilimitada.

Ejemplo:

Table test:
   a character(7)
   b varchar(7)

insert "ok    " to a
insert "ok    " to b

Obtenemos los resultados:

a        | (a)char_length | b     | (b)char_length
----------+----------------+-------+----------------
"ok     "| 7              | "ok"  | 2
ofir_aghai
fuente
55
Si bien MySQL truncará silenciosamente los datos cuando el valor exceda el tamaño de la columna, PostgreSQL no lo hará y generará un error de "valor demasiado largo para el tipo de letra variable (n)".
gsiems