Implicaciones de rendimiento de los tamaños de MySQL VARCHAR


45

¿Existe una diferencia de rendimiento en MySQL entre los tamaños varchar? Por ejemplo, varchar(25)y varchar(64000). Si no es así, ¿hay alguna razón para no declarar todos los varchars con el tamaño máximo solo para garantizar que no se quede sin espacio?


3
+1 esta pregunta se aplica de manera similar a todos los DBMS. Mi observación muchos tamaños de varchar tienden a crecer.
bernd_k

55
No es MySQL, pero esta publicación de blog de Depesz puede responder a su pregunta para PostgreSQL .
xenoterracide

Respuestas:


29

Debe darse cuenta de las ventajas de usar CHAR vs VARCHAR

Con los campos CHAR, lo que asigna es exactamente lo que obtiene. Por ejemplo, CHAR (15) asigna y almacena 15 bytes, sin importar la cantidad de caracteres que coloque en el campo. La manipulación de cadenas es simple y directa ya que el tamaño del campo de datos es totalmente predecible.

Con los campos VARCHAR, obtienes una historia completamente diferente. Por ejemplo, VARCHAR (15) en realidad asigna dinámicamente hasta 16 bytes, hasta 15 para datos y, al menos, 1 byte adicional para almacenar la longitud de los datos. Si tiene la cadena 'hola' para almacenar que tomará 6 bytes, no 5. La manipulación de cadenas siempre debe realizar alguna forma de verificación de longitud en todos los casos.

La compensación es más evidente cuando haces dos cosas:
1. Almacenamiento de millones o miles de millones de filas
2. Columnas de indexación que son CHAR o VARCHAR

COMERCIO # 1

Obviamente, VARCHAR tiene la ventaja ya que los datos de longitud variable producirían filas más pequeñas y, por lo tanto, archivos físicos más pequeños.

COMERCIO # 2

Dado que los campos CHAR requieren menos manipulación de cadenas debido a los anchos de campo fijos, las búsquedas de índice contra el campo CHAR son en promedio un 20% más rápidas que las de los campos VARCHAR. Esta no es ninguna conjetura de mi parte. El libro MySQL Database Design and Tuning realizó algo maravilloso en una tabla MyISAM para probar esto. El ejemplo en el libro hizo algo como lo siguiente:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Esta directiva obliga a los VARCHAR a comportarse como CHAR. Hice esto en mi trabajo anterior en 2007 y tomé una tabla de 300GB y aceleré las búsquedas de índice en un 20%, sin cambiar nada más. Funcionó según lo publicado. Sin embargo, produjo una tabla de casi el doble de tamaño, pero eso simplemente se remonta a la compensación # 1.

Puede analizar los datos que se almacenan para ver qué recomienda MySQL para la definición de columna. Simplemente ejecute lo siguiente en cualquier tabla:

SELECT * FROM tblname PROCEDURE ANALYSE();

Esto atravesará toda la tabla y recomendará definiciones de columna para cada columna en función de los datos que contiene, los valores mínimos de campo, los valores máximos de campo, etc. A veces, solo tiene que usar el sentido común al planificar CHAR vs VARCHAR. Aquí hay un buen ejemplo:

Si está almacenando direcciones IP, la máscara para dicha columna tiene como máximo 15 caracteres (xxx.xxx.xxx.xxx). Saltaría directamente a CHAR (15) en un abrir y cerrar de ojos porque las longitudes de las direcciones IP no variarán demasiado y la complejidad adicional de la manipulación de cadenas controlada por un byte adicional. Todavía podría hacer un ANÁLISIS DE PROCEDIMIENTO () contra dicha columna. Incluso puede recomendar VARCHAR. Mi dinero todavía estaría en CHAR sobre VARCHAR en este caso.

Los problemas de CHAR vs VARCHAR solo se pueden resolver mediante una planificación adecuada. Con gran poder viene una gran responsabilidad (cliché pero cierto)


44
Si almacena direcciones IP, no veo ninguna razón para almacenarlas como algo más que un int. Eso es todo lo que es una dirección IP. Muchos idiomas tienen algún tipo de función ip2int. Si desea la conveniencia de una llamada de línea de comando, no es difícil hacer un procedimiento almacenado para convertir ABCD: A pow (256,3) + b pow (256,2) + c * 256 + d
atxdba

1
Errar más al punto, supongo que mysql tiene su propia función ip2int: INET_ATON
atxdba

3
@atxdba: El punto de mi respuesta es simplemente usar CHAR vs VARCHAR. Solo uso IP como ejemplo porque su tamaño de caracteres de cadena está más cerca de 15. Por lo tanto, redondear un tamaño CHAR estable a favor de VARCHAR es solo un ejemplo en aras de la pregunta en sí. Su comentario sobre mejores formas de representar las direcciones IP es bastante válido y tiene más sentido.
RolandoMySQLDBA

CHAR (15) asigna 15 caracteres , no bytes . Para utf8, eso es 45 bytes .
Rick James

2
Si bien esta es una buena respuesta sobre la comparación CHAR / VARCHAR, la pregunta era sobre diferentes tamaños de VARCHAR.
Coleccionista

13

La respuesta a esto es en realidad bastante compleja. La versión corta: hay una diferencia .

  1. Al crear tablas temporales para filtrar resultados (por ejemplo, GROUP BYdeclaraciones), se asignará la longitud completa.

  2. El protocolo de conexión (que envía filas al cliente) probablemente asignará la longitud más grande.

  3. El motor de almacenamiento puede / no puede implementar un varchar adecuado.

Para (2) admito que el protocolo de conexión no es algo con lo que estoy íntimamente familiarizado, pero el consejo general aquí es intentar y aplicar al menos un mínimo esfuerzo para adivinar la longitud.


Vale la pena señalarlo. MySQL 5.7 puede empaquetar valores en el búfer de clasificación (longitud variable). Explicado con más detalle aquí: mysqlserverteam.com/…
Morgan Tocker

9

La mayoría de las respuestas en este hilo tienen 5 años, escritas antes de que InnoDB y utf8 fueran valores predeterminados. Entonces, déjame comenzar de nuevo ...

Cuando una consulta necesita una tabla temporal interna, intenta usar una MEMORYtabla. Pero MEMORY no se puede usar si

  • TEXT/ BLOBcolumnas que se obtienen, ni siquiera TINYTEXT.
  • VARCHAR mayor que alguna cantidad, probablemente 512 en la versión actual.

Además, tenga en cuenta que VARCHARsse convierten en CHARs. Entonces, VARCHAR(255)con un se CHARACTER SET utf8expande a 765 bytes, independientemente de lo que esté en la columna. Entonces, esto podría activarse:

  • Si la MEMORYtabla se hace más grande que cualquiera max_heap_table_size o tmp_table_size , que se convertirá en MyISAM y potencialmente derrame en el disco.

Por lo tanto, VARCHAR(25)es más probable que se quede MEMORY, por lo tanto, sea más rápido. (255)No es tan bueno y (64000)es malo.

(En el futuro, las tablas temporales probablemente lo serán InnoDB, y parte de esta respuesta deberá revisarse).


6

Una columna varchar de ese tamaño hace que las consultas en toda la tabla sean más propensas a usar tablas temporales. De acuerdo con el libro MySQL de alto rendimiento. Cuando el optimizador intenta ver si puede ejecutar esta consulta en la memoria o si necesita una tabla temporal, observa el tamaño de la fila en función de la definición de la tabla, es decir, en cuanto a la velocidad, no intenta ver cuántos caracteres de 64K en realidad estás usando Esta es la razón por la cual los escritores recomiendan que no extienda esa definición más allá de los posibles valores reales que irían en la columna. Obviamente, si se prepara para más consultas en las tablas temporales (incluso si el tamaño real de los datos podría caber en la RAM), ahora ha incurrido en penalizaciones de E / S que podría haber evitado.


Esa es una perspectiva muy fresca. Si este es el libro al que se refiere ( amazon.com/MySQL-High-Availability-Building-Centers/dp/… ), ingrese el número de página del libro en su respuesta, porque me gustaría leerlo. +1 !!!
RolandoMySQLDBA

Yo tonto ... Alto rendimiento no disponibilidad: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/… ... el número de página es 236/237 Explica cómo la generosidad en la definición de una columna varchar puede ser imprudente. Sin embargo, tenga en cuenta que este libro fue escrito cuando 5.1 acababa de salir. Una tercera edición está saliendo el próximo año para incluir a todos los grandes cambios en 5.5 así que tal vez eso va a cambiar :)
TechieGurl

La página 236 menciona la clasificación que pertenece a conjuntos de caracteres particulares. Eso podría ser un poco desagradable para VARCHAR. En la página 237, la configuración para las comunicaciones cliente / servidor junto con la Figura 5-5 en la página 238 muestran otro motivo. El proceso de traducción de conjuntos de caracteres va y viene. De nuevo, otra desagradable aventura para VARCHAR.
RolandoMySQLDBA

Para aclarar, aunque esta sección no dice directamente que MySQL irá a crear tamaño, sabemos que cuando una operación necesita una tabla temporal, esa tabla está en MEMORY Engine y ESO siempre almacena tipos de cadenas en fragmentos de arreglos, así es como es generoso la definición puede hacer que la tabla temporal MEMORY necesaria vaya al disco en lugar de permanecer en la RAM
TechieGurl

@RolandoMySQLDBA. Sí ... eso también ... la colación también se convierte en un factor aquí (especialmente si usas UTF-8 y tienes caracteres no latinos) y todo simplemente te mata cuando se trata de una mesa de motor de memoria y conduce a un viaje más rápido al disco
TechieGurl

5

Entiendo que los campos más pequeños pueden incluirse directamente en el índice, mientras que los campos más largos no pueden. Debido a esa limitación, si desea que las cadenas sean indexables, diría que las mantenga más cortas. De lo contrario, no, dado que ambos son varchar, las operaciones como ordenar o comparar funcionarán en el mismo tiempo, ya sea que los campos sean 25 o MAX.


3

asegúrese de no quedarse sin espacio

Esta frase implica que hace la pregunta porque no está seguro acerca de los datos que almacenará en la base de datos. Si eso es cierto, será de gran utilidad averiguarlo lo antes posible, porque lo necesitará para planificar la capacidad. Si puede obtener elementos de datos con 7000 caracteres, por ejemplo, debe saberlo porque eso tendría implicaciones de rendimiento en cualquier DBMS.

Dicho esto, prefiero tener tamaños de columna relacionados con el contenido esperado. Por ejemplo, es poco probable que un número de teléfono tenga más de 50 caracteres, incluso si incluye un código de país y una extensión. Del mismo modo, un código postal o postal tendrá 20 caracteres o menos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.