Tengo una columna indexada que almacena un hash MD5. Por lo tanto, la columna siempre almacenará un valor de 32 caracteres. Por alguna razón, esto fue creado como un varchar en lugar de un char. ¿Merece la pena migrar la base de datos para convertirla en un char? Esto está en MySQL 5.0 con InnoDB.
mysql
performance
innodb
varchar
Jason Baker
fuente
fuente
Respuestas:
Se hizo una pregunta similar antes
Implicaciones de rendimiento de los tamaños de MySQL VARCHAR
Aquí está el extracto de mi respuesta.
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
TRADEOFF # 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.
TRADEOFF # 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:
Esta directiva obliga a todos 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 columnas. Simplemente ejecute lo siguiente en cualquier tabla:
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). Me gustaría saltar
CHAR(15)
en un abrir y cerrar de ojos porque las longitudes de las direcciones IP no variarán mucho y la complejidad adicional de la manipulación de cadenas controlada por un byte adicional. Todavía podrías hacer unaPROCEDURE ANALYSE()
contra tal 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 un gran poder viene una gran responsabilidad (cliché pero cierto).
ACTUALIZAR
Cuando se trata de MD5, el cálculo de
strlen
internamente debe eliminarse al cambiar todo el formato de fila. No habría necesidad de cambiar la definición del campo.Si la clave MD5 es el único VARCHAR presente, lo buscaría y convertiría el formato de fila de la tabla a fijo . Si hay un número significativo de otros campos VARCHAR presentes, también se beneficiarían. A cambio, la tabla se expandiría a aproximadamente el doble de su tamaño. Pero las consultas deberían acelerar un 20% más sin ajustes adicionales.
fuente
bit
ybinary
?Parece que ahorrará 1 byte por valor o alrededor del 3% al convertir a
char
. Probablemente no valga la pena si está almacenando MD5 en hexadecimal de todos modos; podría ahorrar un 50% utilizando unbinary
en su lugar.Gracias a Ovais (ver comentarios) por señalar que
char(32)
puede usar mucho más de 32 bytes si está usando un juego de caracteres multibyte.Gracias a Rick James por señalar que debería usar la
unhex
función para convertir una cadena hexadecimal a binario:db <> violín aquí
fuente
binary
, ¿o he entendido mal?BINARY
hace muy poco a menos que también lo useUNHEX()
. Es decir, se puede almacenarUNHEX(MD5(x))
en un 16 bytesBINARY(16)
para ahorrar espacio significativo durante el almacenamientoMD5(x)
enCHAR(32) CHARACTER SET ascii
.No vale la pena cambiar en mi opinión. Si mira la documentación aquí, debería ilustrar la diferencia entre los dos. En su escenario de uso, uno realmente no ofrece ningún beneficio significativo sobre el otro a menos que esté realmente preocupado por la carga adicional relacionada con el tamaño de la fila.
http://dev.mysql.com/doc/refman/5.0/en/char.html
También tenga en cuenta el primer comentario sobre la documentación que enlace arriba ... "CHAR solo acelerará su acceso si todo el registro es de tamaño fijo. Es decir, si usa cualquier objeto de tamaño variable, también podría hacerlos todos tamaño variable. No gana velocidad utilizando un CHAR en una tabla que también contiene un VARCHAR "
fuente