Mejores prácticas para la longitud de la columna varchar de SQL [cerrado]

289

Cada vez que se configura una nueva tabla SQL o se agrega una nueva varcharcolumna a una tabla existente, me pregunto una cosa: cuál es el mejor valor para length.

Entonces, digamos, tiene una columna llamada namede tipo varchar. Entonces, tienes que elegir la longitud. No puedo pensar en un nombre> 20 caracteres, pero nunca lo sabrás. Pero en lugar de usar 20, siempre redondeo al siguiente número 2 ^ n. En este caso, elegiría 32 como la longitud. Hago eso, porque desde el punto de vista de un científico de la computación, un número 2 ^ n me parece más evenque otros números y solo estoy asumiendo que la arquitectura subyacente puede manejar esos números un poco mejor que otros.

Por otro lado, el servidor MSSQL, por ejemplo, establece el valor de longitud predeterminado en 50, cuando elige crear una columna varchar. Eso me hace pensar en eso. ¿Por qué 50? ¿Es solo un número aleatorio, o basado en la longitud promedio de la columna, o qué?

También podría ser, o probablemente lo sea, que diferentes implementaciones de servidores SQL (como MySQL, MSSQL, Postgres, ...) tienen diferentes valores de longitud de columna.

esskar
fuente

Respuestas:

238

Ningún DBMS que conozco tiene alguna "optimización" que haga que un rendimiento VARCHARcon una 2^nlongitud funcione mejor que uno con una maxlongitud que no sea una potencia de 2.

Creo que las primeras versiones de SQL Server en realidad trataban una VARCHARlongitud 255 de forma diferente a una con una longitud máxima más alta. No sé si este sigue siendo el caso.

Para casi todos los DBMS, el almacenamiento real que se requiere solo está determinado por la cantidad de caracteres que ingresa, no por la maxlongitud que define. Entonces, desde el punto de vista del almacenamiento (y probablemente también del rendimiento), no hace ninguna diferencia si declara una columna como VARCHAR(100)o VARCHAR(500).

Debería ver la maxlongitud proporcionada para una VARCHARcolumna como una especie de restricción (o regla comercial) en lugar de una cuestión técnica / física.

Para PostgreSQL, la mejor configuración es usar textsin una restricción de longitud y CHECK CONSTRAINTque limite el número de caracteres a lo que su empresa requiera.

Si ese requisito cambia, alterar la restricción de verificación es mucho más rápido que modificar la tabla (porque la tabla no necesita ser reescrita)

Lo mismo se puede aplicar para Oracle y otros, en Oracle sería en VARCHAR(4000)lugar de eso text.

No sé si hay una diferencia de almacenamiento físico entre VARCHAR(max)y, por ejemplo, VARCHAR(500)en SQL Server. Pero aparentemente hay un impacto en el rendimiento cuando se usa varchar(max)en comparación con varchar(8000).

Ver este enlace (publicado por Erwin Brandstetter como comentario)

Editar 2013-09-22

Con respecto al comentario de bigown:

En Postgres versiones anteriores a 9.2 (que no estaba disponible cuando escribí la respuesta inicial) un cambio en la definición de la columna hizo reescribir toda la tabla, véase, por ejemplo aquí . Dado que 9.2 ya no es así, una prueba rápida confirmó que aumentar el tamaño de la columna para una tabla con 1.2 millones de filas de hecho solo tomó 0.5 segundos.

Para Oracle, esto también parece ser cierto, a juzgar por el tiempo que lleva alterar la varcharcolumna de una gran mesa . Pero no pude encontrar ninguna referencia para eso.

Para MySQL, el manual dice " En la mayoría de los casos, ALTER TABLEhace una copia temporal de la tabla original ". Y mis propias pruebas confirman que: ejecutar ALTER TABLEuna tabla con 1.2 millones de filas (lo mismo que en mi prueba con Postgres) para aumentar el tamaño de una columna tomó 1.5 minutos. En MySQL sin embargo, puede no utilizar la "solución" para utilizar una restricción de comprobación para limitar el número de caracteres en una columna.

Para SQL Server, no pude encontrar una declaración clara sobre esto, pero el tiempo de ejecución para aumentar el tamaño de una varcharcolumna (nuevamente la tabla de 1.2 millones de filas de arriba) indica que no tiene lugar la reescritura.

Editar 2017-01-24

Parece que estaba (al menos parcialmente) equivocado sobre SQL Server. Vea esta respuesta de Aaron Bertrand que muestra que la longitud declarada de una nvarcharo varcharcolumnas hace una gran diferencia en el rendimiento.

un caballo sin nombre
fuente
34
En realidad, hay una diferencia entre VARCHAR (255) y VARCHAR (500), incluso si coloca 1 carácter dentro de dicha columna. El valor agregado al final de la fila será un número entero que almacena la longitud real de los datos almacenados. En el caso de VARCHAR (255) será un entero de 1 byte. En el caso de VARCHAR (500) será de 2 bytes. Es una pequeña diferencia, pero uno debe ser consciente de ello. No tengo datos disponibles sobre cómo puede afectar el rendimiento, pero supongo que es tan pequeño que no vale la pena investigarlo.
NB
1
@NB: a eso me refería para el valor "mágico" 255 de SQL Server. Gracias por la aclaración.
a_horse_with_no_name
44
@NB ¿A qué RDBMS te refieres? ¿Servidor SQL? Hay un efecto en el rendimiento. [N] VARCHAR (máx.) Funciona ligeramente más lento que [N] VARCHAR (n). Recientemente fui referido a este sitio . Lo mismo no es cierto para PostgreSQL por lo que sé.
Erwin Brandstetter
@ErwinBrandstetter: Gracias por el enlace. Parece que varchar(max)probablemente se parece más a OracleCLOB
a_horse_with_no_name
1
Cambiar la longitud de varchar no reescribe la tabla. Simplemente verifica la longitud de la restricción contra toda la tabla exactamente como CHECK CONSTRAINT. Si aumenta la longitud, no hay nada que hacer, solo la próxima inserción o las actualizaciones aceptarán una longitud mayor. Si disminuye la longitud y todas las filas pasan la nueva restricción más pequeña, Pg no toma ninguna otra acción además de permitir que las próximas inserciones o actualizaciones escriban solo la nueva longitud.
Maniero
69

VARCHAR(255)¡y VARCHAR(2)tome exactamente la misma cantidad de espacio en el disco! Entonces, la única razón para limitarlo es si tiene una necesidad específica de que sea más pequeño. De lo contrario, hágalos todos 255.

Específicamente, al ordenar, una columna más grande ocupa más espacio, por lo que si eso perjudica el rendimiento, entonces debe preocuparse y hacerlos más pequeños. Pero si solo selecciona 1 fila de esa tabla, puede hacer que todas sean 255 y no importará.

Ver: ¿Cuáles son los tamaños óptimos de varchar para MySQL?

Ariel
fuente
77
¿Por qué no hacerlos todos VARCHAR(MAX)? El espacio no es la única consideración al modelar una base de datos. El dominio que está modelando debe controlar los tipos de datos y los tamaños.
Oded
66
@Oded VARCHAR(MAX)no es lo mismo que varchar(255)o varchar(65535)- varchar max es un tipo de tipo de textdatos. Y a su punto, si supiera cuál es el "dominio que estaba modelando", no estaría haciendo esta pregunta. Claramente, él no sabe qué tan grandes serán sus datos, y le aseguro que hacerlo a tamaño completo no hace daño.
Ariel
44
@Ariel: También hay problemas y limitaciones en los índices a considerar. No puede tener un (a,b,c,d)índice cuando las cuatro columnas lo son VARCHAR(255).
ypercubeᵀᴹ
@ypercube Eso es cierto, si sus columnas necesitan un índice, debe tener más cuidado con los tamaños. Pero la mayoría de las columnas no necesitan un índice, por lo que la mayoría de las veces no necesita preocuparse por ello.
Ariel
Creo que si sabemos el valor exacto, prefiero usar char. Mientras tanto, si todavía está predicitve i utilizar varchar y mantener 255, ya que es la asignación de memoria dinámica por lo que no se preocupe por el tamaño que se tomará
Faris Rayhan
54

Cada vez que configuro una nueva tabla SQL, siento lo mismo acerca de que 2 ^ n es más "par" ... pero para resumir las respuestas aquí, no hay un impacto significativo en el espacio de almacenamiento simplemente definiendo varchar (2 ^ n) o incluso varchar (MAX).

Dicho esto, aún debe anticipar las posibles implicaciones en el almacenamiento y el rendimiento al establecer un límite alto de varchar (). Por ejemplo, supongamos que crea una columna varchar (MAX) para contener descripciones de productos con indexación de texto completo. Si el 99% de las descripciones tienen solo 500 caracteres de largo, y de repente obtienes a alguien que reemplaza dichas descripciones con artículos de Wikipedia, es posible que notes importantes impactos inesperados de almacenamiento y rendimiento.

Otra cosa a considerar de Bill Karwin :

Hay un posible impacto en el rendimiento: en MySQL, las tablas temporales y las tablas de MEMORIA almacenan una columna VARCHAR como una columna de longitud fija, rellenada hasta su longitud máxima. Si diseña columnas VARCHAR mucho más grandes que el tamaño más grande que necesita, consumirá más memoria de la necesaria. Esto afecta la eficiencia del caché, la velocidad de clasificación, etc.

Básicamente, solo presente restricciones comerciales razonables y errores en un tamaño ligeramente mayor. Como señaló @onedaywhen, los apellidos en el Reino Unido suelen tener entre 1 y 35 caracteres. Si decides convertirlo en varchar (64), en realidad no vas a lastimar nada ... a menos que estés almacenando el apellido de este tipo que se dice que tiene hasta 666 caracteres de longitud. En ese caso, quizás varchar (1028) tiene más sentido.

Y en caso de que sea útil, así es como se vería varchar 2 ^ 5 a 2 ^ 10 si estuviera lleno:

varchar(32)     Lorem ipsum dolor sit amet amet.

varchar(64)     Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie

varchar(128)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas

varchar(256)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt

varchar(512)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt
                dolor tellus, sit amet porta neque varius vitae. Seduse molestie
                lacus id lacinia tempus. Vestibulum accumsan facilisis lorem, et
                mollis diam pretium gravida. In facilisis vitae tortor id vulput
                ate. Proin ornare arcu in sollicitudin pharetra. Crasti molestie

varchar(1024)   Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt
                dolor tellus, sit amet porta neque varius vitae. Seduse molestie
                lacus id lacinia tempus. Vestibulum accumsan facilisis lorem, et
                mollis diam pretium gravida. In facilisis vitae tortor id vulput
                ate. Proin ornare arcu in sollicitudin pharetra. Crasti molestie
                dapibus leo lobortis eleifend. Vivamus vitae diam turpis. Vivamu
                nec tristique magna, vel tincidunt diam. Maecenas elementum semi
                quam. In ut est porttitor, sagittis nulla id, fermentum turpist.
                Curabitur pretium nibh a imperdiet cursus. Sed at vulputate este
                proin fermentum pretium justo, ac malesuada eros et Pellentesque
                vulputate hendrerit molestie. Aenean imperdiet a enim at finibus
                fusce ut ullamcorper risus, a cursus massa. Nunc non dapibus vel
                Lorem ipsum dolor sit amet, consectetur Praesent ut ultrices sit
Equipo
fuente
31

El mejor valor es el correcto para los datos tal como se define en el dominio subyacente.

Para algunos dominios, VARCHAR(10)es adecuado para el Nameatributo, para otros dominios VARCHAR(255)podría ser la mejor opción.

Oded
fuente
15

Agregando a la respuesta de a_horse_with_no_name puede encontrar lo siguiente de interés ...

no importa si declara una columna como VARCHAR (100) o VACHAR (500).

-- try to create a table with max varchar length
drop table if exists foo;
create table foo(name varchar(65535) not null)engine=innodb;

MySQL Database Error: Row size too large.

-- try to create a table with max varchar length - 2 bytes for the length
drop table if exists foo;
create table foo(name varchar(65533) not null)engine=innodb;

Executed Successfully

-- try to create a table with max varchar length with nullable field
drop table if exists foo;
create table foo(name varchar(65533))engine=innodb;

MySQL Database Error: Row size too large.

-- try to create a table with max varchar length with nullable field
drop table if exists foo;
create table foo(name varchar(65532))engine=innodb;

Executed Successfully

No olvide el byte (s) de longitud y el byte anulable, entonces:

name varchar(100) not null será de 1 byte (longitud) + hasta 100 caracteres (latin1)

name varchar(500) not null será de 2 bytes (longitud) + hasta 500 caracteres (latin1)

name varchar(65533) not null será de 2 bytes (longitud) + hasta 65533 caracteres (latin1)

name varchar(65532) será de 2 bytes (longitud) + hasta 65532 caracteres (latin1) + 1 byte nulo

Espero que esto ayude :)

Jon Black
fuente
Estás utilizando MySQL, y la pregunta es acerca de MSSQL
Bogdan Mart
3

No he comprobado esto últimamente, pero sé en el pasado con Oracle que el controlador JDBC reservaría un trozo de memoria durante la ejecución de la consulta para retener el conjunto de resultados. El tamaño del fragmento de memoria depende de las definiciones de columna y del tamaño de recuperación. Entonces, la longitud de las columnas varchar2 afecta la cantidad de memoria reservada. Esto me causó serios problemas de rendimiento hace años, ya que siempre usamos varchar2 (4000) (el máximo en ese momento) y la recolección de basura era mucho menos eficiente de lo que es hoy.

usuario1041892
fuente
-2

En cierto sentido, tiene razón, aunque cualquier cosa inferior a 2 ^ 8 caracteres aún se registrará como un byte de datos.

Si tiene en cuenta el carácter base que deja cualquier cosa con un VARCHAR <255 como que consume la misma cantidad de espacio.

255 es una buena definición de línea de base a menos que desee especialmente reducir la entrada excesiva.

Dale Willis
fuente
" aunque algo más bajo que 2 ^ 8 caracteres todavía se registrará como un byte de datos " - incorrecto. La base de datos solo almacena tantos caracteres como se proporcionan en un tipo VARCHAR. No hay espacio "registrado", reservado o inicializado al declarar una columna.
a_horse_with_no_name