Saltar al contenido

MySQL: longitud y rendimiento de varchar

Posterior a de una larga recopilación de información dimos con la solución este enigma que presentan muchos usuarios. Te compartimos la solución y nuestro deseo es servirte de mucha ayuda.

Solución:

Esta es una “pregunta de examen/entrevista” muy común. Responderé lo mejor que pueda:

En los formatos de fila estándar para InnoDB y MyISAM (dinámico/compacto) un VARCHAR(50) y un VARCHAR(255) almacenará el string texto de la misma manera- 1 byte para la longitud y el real string con entre 1 y 4 bytes por carácter (dependiendo de la codificación y el carácter real almacenado).

De hecho, si no recuerdo mal, recuerdo que alguien modificó el diccionario de datos con un editor hexadecimal para cambiar algo como un VARCHAR(50) en un VARCHAR(100), por lo que podría hacerse dinámicamente (normalmente, eso requiere una reconstrucción de la tabla). Y eso fue posible, porque los datos reales no se vieron afectados por ese cambio.

Eso no es true con VARCHAR(256)porque siempre se requieren 2 bytes (al menos) para la longitud.

Entonces, eso significa que siempre debemos hacer VARCHAR(255), ¿no deberíamos? No. Hay varias razones.

Si bien InnoDB puede almacenar un varchar de forma dinámica, eso no es true para otros motores. MyISAM tiene un formato de tamaño de fila fijo y las tablas MEMORY siempre tienen un tamaño fijo. ¿Deberíamos preocuparnos por esos otros motores? Sí, deberíamos, porque incluso si no los usamos directamente, Las tablas MEMORY se usan muy comúnmente para resultados intermedios (tablas temporales en memoria)y como los resultados no se conocen de antemano, la tabla debe crearse con el tamaño máximo posible:VARCHAR(255) si ese es nuestro tipo. Si puedes pensar en el espacio desperdiciado, si estamos usando MySQL 'utf8' charset codificación, MEMORY reservará 2 bytes para la longitud + 3 * 255 bytes por fila (para valores que solo pueden tomar unos pocos bytes en InnoDB). Eso es casi 1 GB en una tabla de 1 millón, solo para VARCHAR. Esto no solo provoca un estrés innecesario en la memoria, sino que puede provocar que las acciones se realicen en el disco, lo que podría ralentizarlo miles de veces. Todo ello por una mala selección de su tipo de dato definido (independientemente del contenido).

También tiene algunas consecuencias para InnoDB. El tamaño del índice está restringido a 3072 bytes y los índices de una sola columna, a 767 bytes*. Entonces, es muy probable que no pueda indexar completamente un VARCHAR(255) (asumiendo que usa utf8 o cualquier otra codificación de longitud variable).

Además, el tamaño máximo de fila en línea para InnoDB es media página (alrededor de 8000 bytes) y campos de longitud variable como BLOB o varchar, se pueden almacenar fuera de la página si no caben en la mitad de la página. Eso tiene algunas consecuencias en el rendimiento (a veces buenas, a veces malas, según el uso) que no se pueden ignorar. Esto causó cierta rareza entre los formatos COMPACTO y DINÁMICO. Véase, por ejemplo: error 1118: tamaño de fila demasiado grande. innodb utf8

Por último, pero no menos importante, como @ypercube me ha recordado, es posible que se requiera más de 1 byte para la longitud, incluso si está utilizando VARCHAR(255), porque la definición está en caracteres, mientras que la longitud almacena bytes. Por ejemplo REPEAT('ñ', 255) tiene más de 2^255 bytes en utf8, por lo que requeriría más de 1 byte para almacenar su longitud:

mysql> SELECT LENGTH(REPEAT('ñ', 255));
+---------------------------+
| LENGTH(REPEAT('ñ', 255))  |
+---------------------------+
|                       510 |
+---------------------------+
1 row in set (0.02 sec)

mysql> SELECT CHAR_LENGTH(REPEAT('ñ', 255));
+--------------------------------+
| CHAR_LENGTH(REPEAT('ñ', 255))  |
+--------------------------------+
|                            255 |
+--------------------------------+
1 row in set (0.00 sec)

Así que el consejo general es use el tipo más pequeño posible, porque de lo contrario puede crear problemas de rendimiento o de gestión. A VARCHAR(100) es mejor que VARCHAR(255) (aunque un VARCHAR(20) sería mejor), incluso si no conoce la longitud exacta. Trate de ser conservador porque, a menos que la tabla sea demasiado grande, siempre puede cambiar la definición más adelante.

Actualizar: Debido a la creciente popularidad de las cadenas de longitud variable, por ejemplo, con el uso de emojis, Oracle ha estado presionando para mejorar el rendimiento en esos casos. En las últimas versiones de MySQL (5.6, 5.7), InnoDB se ha establecido como el motor predeterminado para las tablas temporales intrínsecas y explícitas, lo que significa que los campos de longitud variable ahora son ciudadanos de primera clase. Eso significa que puede haber menos razones para tener longitudes de caracteres muy restringidas (pero aún existen).

Segunda actualización true : large_prefix_index ahora está habilitado de forma predeterminada en las últimas versiones de MySQL (8.0), pero eso sigue siendo

para versiones anteriores o si está utilizando formatos de archivo/fila Lagacy innodb (que no sean dinámicos o comprimidos), pero ahora, de forma predeterminada, los índices de una sola columna pueden tener hasta esos 3072 bytes.

Ten en cuenta dar recomendación a esta reseña si si solucionó tu problema.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *