MySQL: longitud y rendimiento de varchar


Respuestas:


31

Esta es una "pregunta de examen / entrevista" muy común. Contestaré lo mejor que pueda:

En los formatos de fila estándar para InnoDB y MyISAM (dinámico / compacto), a VARCHAR(50)y a VARCHAR(255)almacenará el texto de la cadena de la misma manera: 1 byte para la longitud y la cadena real 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 a VARCHAR(50)en a 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 cierto con VARCHAR(256), porque entonces siempre se requieren 2 bytes (al menos) para la longitud.

Entonces, eso significa que siempre debemos hacerlo VARCHAR(255), ¿no? No. Hay varias razones.

Si bien InnoDB puede almacenar un varchar de forma dinámica, eso no es cierto para otros motores. MyISAM tiene un formato de tamaño de fila fijo, y las tablas de MEMORIA 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 de MEMORIA se usan muy comúnmente para resultados intermedios (tablas temporales en la 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 puede pensar en el espacio perdido, si estamos utilizando la 'utf8' charsetcodificación de MySQL , 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 mesa de 1 millón, solo para VARCHAR. No solo esto causa un estrés innecesario en la memoria, sino que puede provocar que las acciones se realicen en el disco, lo que puede ralentizarlo miles de veces. Todo eso debido a una mala selección de su tipo de datos definido (independientemente de los contenidos).

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 *. Por loVARCHAR(255) tanto, es muy probable que no pueda indexar completamente un campo (suponiendo que use 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 los campos de longitud variable como BLOB o varchar, se pueden almacenar fuera de la página si no caben en la media página . Eso tiene algunas consecuencias en el rendimiento (a veces buenas, a veces malas, dependiendo del uso) que no se pueden ignorar. Esto causó cierta rareza entre los formatos COMPACT y DYNAMIC. Ver, por ejemplo: error 1118: tamaño de fila demasiado grande. utf8 innodb

Por último, pero no menos importante, como me ha recordado @ypercube, puede ser necesario 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)

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

Actualización: debido a la gran 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 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 limitadas (pero aún existen).

(*) Segunda actualización : large_prefix_index ahora está habilitado de forma predeterminada en las últimas versiones de MySQL (8.0), pero eso sigue siendo cierto para las versiones anteriores o si está utilizando formatos de archivo / fila innodb heredados (que no sean dinámicos o comprimidos), pero ahora de forma predeterminada, los índices de una sola columna pueden tener hasta esos 3072 bytes.


pequeña actualización: MySQL-8.0.13 + usa TempTable de forma predeterminada para tablas temporales que tiene un almacenamiento eficiente para varchars.
danblack

0

Olvídate del prefijo de 1 contra 2 bytes VARCHARs.

  • Afecta el rendimiento en una cantidad minúscula.
  • Es "2" con más frecuencia de lo que dice la regla obvia.

La pregunta sobre 255 ha sido formulada y respondida muchas veces.

  • Demasiado tiempo VARCHARspuede conducir al fracaso de CREATE TABLE.
  • Las tablas temporales pueden convertirse en MEMORYtablas, con VARCHARsconvertidas en VARCHAR. Esto significa, por ejemplo, que VARCHAR(255) CHARACTER SET utf8mb4quiere una longitud fija de 1020 bytes. (Esto fallará y degenerará al usar MyISAM).

En pocas palabras: no use ciegamente 255 (o 256); haz lo que tenga sentido para el esquema.

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.