¿Existen desventajas al usar un varchar genérico (255) para todos los campos basados ​​en texto?

100

Tengo una contactstabla que contiene campos tales como postcode, first name, last name, town, country, phone numberetc, todos los cuales se definen como VARCHAR(255)a pesar de que ninguno de estos campos nunca se acercará a tener 255 caracteres. (Si se está preguntando, es así porque las migraciones de Ruby on Rails asignan campos de cadena a VARCHAR(255)de forma predeterminada y nunca me molesté en anularlo).

Dado que VARCHAR solo almacenará el número de caracteres reales del campo (junto con la longitud del campo), ¿hay alguna ventaja distintiva (de rendimiento o de otro tipo) en usar, digamos, VARCHAR(16)over VARCHAR(255)?

Además, la mayoría de estos campos tienen índices. ¿Un tamaño de VARCHAR más grande en el campo afecta en absoluto el tamaño o el rendimiento del índice?

Para su información, estoy usando MySQL 5.

Olly
fuente
2
@ceejayoz, decir que la respuesta aceptada es incorrecta sin explicar por qué realmente no ayuda. Lo que lo hace aún peor es que la respuesta aceptada puede cambiar con el tiempo y su comentario confundirá a la gente haciéndoles pensar que la nueva respuesta aceptada es incorrecta.
Gili
1
@Gili eliminó mi comentario ya que el OP aparentemente cambió su aceptación. Buenos puntos, en el futuro indicaré de qué respuesta estoy hablando y por qué.
ceejayoz
Algunas otras respuestas a esta pregunta duplicada, stackoverflow.com/questions/1262174/…
James McMahon

Respuestas:

129

En almacenamiento, VARCHAR(255)es lo suficientemente inteligente como para almacenar solo la longitud que necesita en una fila determinada, a diferencia de CHAR(255)lo que siempre almacenaría 255 caracteres.

Pero como etiquetó esta pregunta con MySQL, mencionaré un consejo específico de MySQL: a medida que las filas se copian desde la capa del motor de almacenamiento a la capa SQL, los VARCHARcampos se convierten CHARpara obtener la ventaja de trabajar con filas de ancho fijo. Entonces, las cadenas en la memoria se rellenan hasta la longitud máxima de su VARCHARcolumna declarada .

Cuando su consulta genera implícitamente una tabla temporal, por ejemplo, mientras ordena o GROUP BY, esto puede usar mucha memoria. Si usa muchos VARCHAR(255)campos para datos que no necesitan ser tan largos, esto puede hacer que la tabla temporal sea muy grande.

También puede interesarle saber que este comportamiento de "relleno" significa que una cadena declarada con el juego de caracteres utf8 se reduce a tres bytes por carácter, incluso para las cadenas que almacena con contenido de un solo byte (por ejemplo, caracteres ascii o latin1). Y del mismo modo, el juego de caracteres utf8mb4 hace que la cadena se rellene hasta cuatro bytes por carácter en la memoria.

Entonces, VARCHAR(255)en utf8 almacenar una cadena corta como "Sin opinión" toma 11 bytes en el disco (diez caracteres de juego de caracteres inferiores, más un byte de longitud) pero toma 765 bytes en memoria y, por lo tanto, en tablas temporales o resultados ordenados.

He ayudado a usuarios de MySQL que, sin saberlo, creaban tablas temporales de 1,5 GB con frecuencia y ocupaban su espacio en disco. Tenían muchas VARCHAR(255)columnas que en la práctica almacenaban cadenas muy cortas.

Es mejor definir la columna según el tipo de datos que desea almacenar. Tiene beneficios para hacer cumplir las restricciones relacionadas con la aplicación, como han mencionado otras personas. Pero tiene los beneficios físicos para evitar el desperdicio de memoria que describí anteriormente.

Es difícil saber cuál es la dirección postal más larga, por supuesto, por lo que muchas personas eligen una dirección larga VARCHARque ciertamente es más larga que cualquier dirección. Y 255 es habitual porque es la longitud máxima de a VARCHARpara la que la longitud se puede codificar con un byte. También fue la VARCHARlongitud máxima en MySQL anterior a 5.0.

Bill Karwin
fuente
6
Siempre pensé que 255se usaba para que la longitud de la cadena pudiera caber en un solo byte
BlueRaja - Danny Pflughoeft
3
@BlueRaja: Eso fue probablemente cierto para las bases de datos cuya estructura de archivos interna codificaba la longitud de una cadena en un solo byte, o si codificaban cadenas cortas en un solo byte. Pero ya no es cierto para la mayoría de las bases de datos.
Bill Karwin
7
@BlueRaja: InnoDB no almacena la longitud del siguiente varchar, almacena una serie de compensaciones de campo para todos los campos de la fila. Estos desplazamientos de campo pueden ser de 1 byte si el tamaño total de la fila es inferior a 127 bytes, o bien 2 bytes. Ver forge.mysql.com/wiki/MySQL_Internals_InnoDB
Bill Karwin
6
@BlueRaja: MyISAM (para aquellos que todavía lo usan) almacena longitudes varchar, y estas se pueden almacenar en 1 o 2 bytes. Sin embargo: "Cuando enviamos una clave al controlador para index_read () o records_in_range, siempre usamos una longitud de 2 bytes para VARCHAR para simplificar las cosas". Ver forge.mysql.com/wiki/MySQL_Internals_MyISAM
Bill Karwin
1
una pregunta: ¿ordenar y agrupar en cualquier campo o en el campo varchar mismo?
Rohit Banga
24

Además de las consideraciones de tamaño y rendimiento de establecer el tamaño de un varchar (y posiblemente más importante, ya que el almacenamiento y el procesamiento se abaratan cada segundo), la desventaja de usar varchar (255) "solo porque" es la integridad de los datos reducida .

Definir límites máximos para cadenas es algo bueno para evitar que cadenas más largas de lo esperado ingresen al RDBMS y causen desbordes de búfer o excepciones / errores más adelante al recuperar y analizar valores de la base de datos que son más largos (más bytes) de lo esperado.

Por ejemplo, si tiene un campo que acepta cadenas de dos caracteres para abreviaturas de países, no tiene ninguna razón concebible para esperar que sus usuarios (en este contexto, programadores) ingresen nombres completos de países. Como no desea que ingresen "Antigua y Barbuda" (AG) o "Islas Heard y McDonald" (HM), no lo permite en la capa de la base de datos. Además, es probable que algunos programadores aún no hayan RTFMed la documentación de diseño ( que seguramente existe ) para saber que no deben hacer esto.

Configure el campo para que acepte dos caracteres y deje que el RDBMS lo maneje (ya sea con gracia truncando o sin gracia al rechazar su SQL con un error).

Ejemplos de datos reales que no tienen por qué superar una determinada longitud:

  • Los códigos postales canadienses tienen el formato A1A1A1 y siempre tienen 6 caracteres de longitud, incluso para Papá Noel (6 caracteres excluyen el espacio que se puede especificar por legibilidad).
  • direcciones de correo electrónico : hasta 64 bytes antes de @, hasta 255 bytes después. Nunca más, para que no rompa Internet.
  • Los números de teléfono de América del Norte nunca tienen más de 10 dígitos (excluyendo el código de país).
  • Los equipos que ejecutan (versiones recientes de) Windows no pueden tener nombres de equipo de más de 63 bytes , aunque no se recomiendan más de 15 y romperán su conjunto de servidores de Windows NT.
  • Las abreviaturas de los estados tienen 2 caracteres (como los códigos de país que se muestran arriba)
  • Los números de seguimiento de UPS tienen 18, 12, 11 o 9 caracteres. Los números de 18 caracteres comienzan con "1Z" y los números de 11 caracteres comienzan con "T", lo que hace que se pregunte cómo entregan todos esos paquetes si no conocen la diferencia entre letras y números.

Y así...

Tómese el tiempo para pensar en sus datos y sus límites. Si eres arquitecto, desarrollador o programador , después de todo , es tu trabajo .

Al usar varchar (n) en lugar de varchar (255), elimina el problema donde los usuarios (usuarios finales, programadores, otros programas) ingresan datos inesperadamente largos que volverán a atormentar su código más adelante.

Y no dije que no debas implementar también esta restricción en el código de lógica empresarial que usa tu aplicación.

shufler
fuente
5
Los códigos postales canadienses en realidad tienen 7 dígitos, el espacio en el medio es importante y debe mostrarse en las etiquetas postales. Los números de teléfono de América del Norte pueden tener más de 10 dígitos si hay una extensión. Si está bien no poder almacenar extensiones de números de teléfono, entonces 10 dígitos está bien, pero probablemente se arrepienta.
Kibbee
3
Definitivamente hay razones para restringir la integridad de los datos. Sin embargo, sigue siendo fácil ser demasiado restrictivo. Imponga restricciones para los datos que controla e imponga restricciones sensatas para los requisitos de datos que no puede controlar. Sus restricciones de número de teléfono y correo electrónico son sensatas (suponiendo que nunca se internacionalice). Su requisito que dice que truncar un código de país de dos caracteres es lo "elegante" es una locura. Sabes que hubo un error, no trunques y acepta. Si trunca, existe una probabilidad extremadamente alta de que termine con un código de país incorrecto.
coderjoe
La mayoría de las aplicaciones tendrán la validación de datos antes de enviarla a la base de datos ...
Cobby
2
Por supuesto. Más. Pero creo que aquí está asumiendo que un desarrollador que está desarrollando una nueva aplicación para una base de datos existente es consciente de las restricciones sobre los datos (no todos somos expertos en cada tipo de datos y cómo se implementan en cada base de datos ). El hecho de que pueda validar datos en su aplicación no significa que lo haya hecho.
shufler
3
the design documentation (which surely exists)Ja. : D
Camilo Martin
14

Estoy contigo. La atención exigente a los detalles es un dolor de cabeza y tiene un valor limitado.

Érase una vez, el disco era un bien preciado y solíamos sudar mucho para optimizarlo. El precio del almacenamiento se ha reducido en un factor de 1.000, lo que hace que el tiempo dedicado a exprimir cada byte sea menos valioso.

Si usa solo campos CHAR, puede obtener filas de longitud fija. Esto puede ahorrar algunos cambios en el estado real del disco si seleccionó tamaños precisos para los campos. Es posible que obtenga datos más densamente empaquetados (menos E / S para escaneos de tablas) y actualizaciones más rápidas (más fácil de ubicar espacios abiertos en un bloque para actualizaciones e inserciones).

Sin embargo, si sobreestima sus tamaños, o si los tamaños reales de sus datos son variables, terminará desperdiciando espacio con los campos CHAR. Los datos terminarán empaquetados menos densamente (lo que generará más E / S para grandes recuperaciones).

Generalmente, los beneficios de rendimiento de intentar asignar un tamaño a los campos variables son menores. Puede comparar fácilmente utilizando VARCHAR (255) en comparación con CHAR (x) para ver si puede medir la diferencia.

Sin embargo, a veces, necesito proporcionar una pista "pequeña", "mediana", "grande". Entonces uso 16, 64 y 255 para los tamaños.

S.Lott
fuente
13

Hoy en día, no puedo imaginar que realmente importe más.

Hay una sobrecarga computacional al usar campos de longitud variable, pero con los excesos de CPU en la actualidad, ni siquiera vale la pena considerarlo. El sistema de E / S es tan lento que hace que los costos computacionales para manejar varchars sean efectivamente inexistentes. De hecho, el precio de un varchar computacionalmente es probablemente una ganancia neta sobre la cantidad de espacio en disco que se ahorra al usar campos de longitud variable sobre campos de longitud fija. Lo más probable es que tenga una mayor densidad de filas.

Ahora, la complejidad de los campos varchar es que no se puede localizar fácilmente un registro a través de su número de registro. Cuando tiene un tamaño de fila de longitud fija (con campos de longitud fija), es trivial calcular el bloque de disco al que apunta una identificación de fila. Con un tamaño de fila de longitud variable, eso se pierde por la ventana.

Entonces, ahora necesita mantener algún tipo de índice de número de registro, como cualquier otra clave primaria, O necesita hacer un identificador de fila robusto que codifique detalles (como el bloque, etc.) en el identificador. Sin embargo, si hace eso, la identificación tendrá que volver a calcularse si alguna vez la fila se mueve al almacenamiento persistente. No es gran cosa, solo necesita reescribir todas las entradas del índice y asegurarse de que a) nunca lo exponga al consumidor ob) nunca afirme que el número es confiable.

Pero dado que tenemos campos varchar hoy, el único valor de varchar (16) sobre varchar (255) es que la base de datos aplicará el límite de 16 caracteres en varchar (16). Si se supone que el modelo de base de datos es realmente representativo del modelo de datos físicos, entonces puede ser valioso tener campos de longitud. Sin embargo, si es simplemente "almacenamiento" en lugar de un "modelo Y almacenamiento", no hay ninguna necesidad.

Luego, simplemente necesita discernir entre un campo de texto que es indexable (como varchar) y algo que no lo es (como un campo de texto o CLOB). Los campos indexables tienden a tener un límite de tamaño para facilitar el índice, mientras que los campos CLOB no lo tienen (dentro de lo razonable).

Will Hartung
fuente
5

En mi experiencia, si permite un tipo de datos de 255 caracteres, algún usuario estúpido (o algún probador experimentado) realmente lo completará.

Luego, tiene todo tipo de problemas, incluido el espacio que permite para esos campos en los informes y las visualizaciones en pantalla de su aplicación. Sin mencionar la posibilidad de exceder el límite por fila de datos en su base de datos (si tuviera más de algunos de estos campos de 255 caracteres).

Es mucho más fácil elegir un límite razonable al principio y luego aplicarlo a través de la aplicación y la base de datos.

BradC
fuente
0

Es una buena práctica asignar solo un poco más de lo que necesita. Los números de teléfono nunca llegarían a ser tan grandes.

Una razón es que, a menos que valide contra entradas grandes, sin duda alguien usará todo lo que haya. Entonces puede que te quedes sin espacio en tu fila. No estoy seguro del límite de MySQL, pero 8060 es el tamaño máximo de filas en MS SQL.

Un valor predeterminado más normal sería 50 en mi humilde opinión, y luego aumentar donde la necesidad lo demuestre.

paloma
fuente
Gracias. Definitivamente estoy de acuerdo en que es una buena práctica. Es el aspecto de rendimiento sobre el que realmente me gustaría una aclaración
Olly
0

En un contexto de mysql, puede ser importante cuando se trabaja con índices en dichas columnas varchar, ya que mysql tiene un max. límite de 767 bytes por fila de índice.

Esto significa que al agregar un índice en varias columnas varchar 255, puede llegar a este límite bastante rápido / incluso más rápido en las columnas utf8 o utf8mb4 como se señaló en las respuestas anteriores

staabm
fuente