215 votos

Diferencia entre texto y varchar (carácter variable)

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

Según la documentación

Si se utiliza character varying sin un especificador de longitud, el tipo acepta cadenas de cualquier tamaño. Esto último es una extensión de PostgreSQL.

y

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

Entonces, ¿cuál es la diferencia?

258voto

Frank Heikens Puntos 29270

No hay diferencia, en realidad todo es varlena (array de longitud variable).

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

Algunos puntos destacados:

Para resumirlo todo:

  • char(n) – ocupa mucho espacio cuando se trata de valores más cortos que n (los rellena hasta n), y puede llevar a errores sutiles por añadir espacios finales, además es problemático cambiar el límite
  • varchar(n) – es problemático cambiar el límite en un entorno en vivo (requiere un bloqueo exclusivo al alterar la tabla)
  • varchar – igual que text
  • text – para mí el ganador – sobre los tipos de datos (n) 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 inserciones y selecciones para los 4 tipos de datos es similar. También analiza detalladamente formas alternativas de restringir la longitud cuando sea necesario. Las restricciones basadas en funciones o dominios proporcionan la ventaja de un aumento instantáneo de la restricción de longitud, y partiendo de la base de que disminuir una restricción de longitud de cadena es raro, depesz concluye que uno de ellos suele ser la mejor elección para un límite de longitud.

91voto

Peter Krauss Puntos 1888

(esta respuesta es un Wiki, puedes editar - ¡por favor, corrige y mejora!)

ACTUALIZACIÓN DE BENCHMARKS PARA 2016 (página 9.5+)

Y utilizando benchmarks "pure SQL" (sin ningún script externo)

  1. utilizar cualquier generador de cadenas con UTF8

  2. principales benchmarks:

2.1. INSERTAR

2.2. SELECCIONAR 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 utilizar EXPLAIN ANALYZE.

ACTUALIZADO NUEVAMENTE 2018 (página 10)

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


Resultados en 2016 y 2018

Mis resultados, después de promediar, en muchas máquinas y muchas pruebas: todos iguales
(estadísticamente menos que la desviación estándar).

Recomendación

  • Usar el tipo de dato text,
    evitar el antiguo varchar(x) porque a veces no es estándar, por ejemplo en cláusulas de CREATE FUNCTION varchar(x)varchar(y).

  • expresar límites (¡con el mismo rendimiento de varchar!) con la cláusula CHECK en el CREATE TABLE
    por ejemplo CHECK(char_length(x)<=10).
    Con una pérdida de rendimiento negligible en INSERT/UPDATE también puede controlar rangos y estructura de cadena
    por ejemplo CHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')

74voto

George Puntos 945

Como se señala en la documentación de "Tipos de Caracteres", varchar(n), char(n) y text se almacenan de la misma manera. La única diferencia es que se necesitan ciclos adicionales para verificar la longitud, si se da una, y el espacio y tiempo adicionales requeridos si se necesita relleno para char(n).

Sin embargo, cuando solo necesitas almacenar un solo carácter, hay una ligera ventaja de rendimiento al usar el tipo especial "char" (mantén las comillas dobles, ya que forman parte del nombre del tipo). Tendrás un acceso más rápido al campo y no habrá sobrecarga para almacenar la longitud.

Acabo de crear una tabla de 1,000,000 de "char" aleatorios elegidos del alfabeto en minúsculas. Una consulta para obtener una distribución de frecuencia (select count(*), campo ... group by campo) toma alrededor de 650 milisegundos, en comparación con aproximadamente 760 con los mismos datos utilizando un campo de text.

49voto

En el manual de PostgreSQL

No hay diferencia de rendimiento entre estos tres tipos, aparte del espacio de almacenamiento adicional al usar el tipo con relleno en blanco, y unos cuantos ciclos de CPU extra para verificar la longitud al almacenar en una columna de longitud restringida. Mientras que character(n) tiene ventajas de rendimiento en algunos otros sistemas de bases de datos, no hay tal ventaja en PostgreSQL; de hecho, character(n) suele ser el más lento de los tres debido a sus costos de almacenamiento adicionales. En la mayoría de las situaciones debería usarse text o character varying en su lugar.

Normalmente uso text

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

31voto

sotn Puntos 1330

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

TL;DR: Si utilizas el tipo text sin una restricción y tienes índices en estas columnas, es muy posible que llegues a este límite para algunas de tus columnas y obtengas un error cuando intentes insertar datos, pero al usar varchar(n), puedes prevenirlo.

Algunos detalles adicionales: El problema aquí es que PostgreSQL no da excepciones al crear índices para el tipo text o varchar(n) donde n es mayor que 2712. Sin embargo, dará error cuando se intente insertar un registro con un tamaño comprimido mayor de 2712. Esto significa que puedes insertar 100.000 caracteres de cadena que están compuestos por caracteres repetitivos fácilmente porque se comprimirán muy por debajo de 2712, pero es posible que no puedas insertar una cadena con 4000 caracteres porque el tamaño comprimido es mayor de 2712 bytes. Al usar varchar(n) donde n no es demasiado mayor que 2712, estarás a salvo de estos errores.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X