2012-01-05 10 views
47

Sé que las preguntas con este título han sido respondidas anteriormente, pero lean. He leído detenidamente todas las demás preguntas/respuestas sobre este error antes de publicarlas.# 1071 - La clave especificada era demasiado larga; la longitud máxima de la clave es 1000 bytes

estoy recibiendo el error anterior para la siguiente consulta:

CREATE TABLE IF NOT EXISTS `pds_core_menu_items` (
    `menu_id` varchar(32) NOT NULL, 
    `parent_menu_id` int(32) unsigned DEFAULT NULL, 
    `menu_name` varchar(255) DEFAULT NULL, 
    `menu_link` varchar(255) DEFAULT NULL, 
    `plugin` varchar(255) DEFAULT NULL, 
    `menu_type` int(1) DEFAULT NULL, 
    `extend` varchar(255) DEFAULT NULL, 
    `new_window` int(1) DEFAULT NULL, 
    `rank` int(100) DEFAULT NULL, 
    `hide` int(1) DEFAULT NULL, 
    `template_id` int(32) unsigned DEFAULT NULL, 
    `alias` varchar(255) DEFAULT NULL, 
    `layout` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`menu_id`), 
    KEY `index` (`parent_menu_id`,`menu_link`,`plugin`,`alias`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

¿Alguien tiene idea de por qué y cómo solucionarlo? El problema es que esta misma consulta funciona perfectamente en mi máquina local y funcionó tan bien en mi host anterior. Btw.it es de un proyecto maduro - phpdevshell - así que supongo que estos tipos saben lo que están haciendo, aunque nunca se sabe.

Cualquier pista apreciada.

Estoy usando phpMyAdmin.

Respuesta

94

Como dice @Devart, la longitud total de su índice es demasiado larga.

La respuesta corta es que no debe indexar columnas VARCHAR tan largas de todos modos, porque el índice será muy voluminoso e ineficiente.

La mejor práctica es usar índices de prefijo, por lo que solo está indexando una subcadena izquierda de los datos. La mayoría de sus datos serán mucho más cortos que 255 caracteres de todos modos.

Puede declarar una longitud de prefijo por columna a medida que define el índice. Por ejemplo:

... 
KEY `index` (`parent_menu_id`,`menu_link`(50),`plugin`(50),`alias`(50)) 
... 

Pero, ¿cuál es la mejor longitud de prefijo para una columna determinada? He aquí un método para averiguar:

SELECT 
ROUND(SUM(LENGTH(`menu_link`)<10)*100/COUNT(*),2) AS pct_length_10, 
ROUND(SUM(LENGTH(`menu_link`)<20)*100/COUNT(*),2) AS pct_length_20, 
ROUND(SUM(LENGTH(`menu_link`)<50)*100/COUNT(*),2) AS pct_length_50, 
ROUND(SUM(LENGTH(`menu_link`)<100)*100/COUNT(*),2) AS pct_length_100 
FROM `pds_core_menu_items`; 

Se da a conocer la proporción de filas que tienen no más de una longitud de cadena indicado en la columna de la menu_link. Es posible que vea una salida como ésta:

+---------------+---------------+---------------+----------------+ 
| pct_length_10 | pct_length_20 | pct_length_50 | pct_length_100 | 
+---------------+---------------+---------------+----------------+ 
|   21.78 |   80.20 |  100.00 |   100.00 | 
+---------------+---------------+---------------+----------------+ 

Esto le indica que el 80% de sus cadenas son menos de 20 caracteres, y todas sus cuerdas están a menos de 50 caracteres. Por lo tanto, no es necesario indexar más de una longitud de prefijo de 50, y ciertamente no es necesario indexar la longitud total de 255 caracteres.

PD: Los tipos de datos INT(1) y INT(32) indican otro malentendido acerca de MySQL. El argumento numérico no tiene ningún efecto relacionado con el almacenamiento o el rango de valores permitido para la columna.INT siempre es de 4 bytes, y siempre permite valores de -2147483648 a 2147483647. El argumento numérico es sobre los valores de relleno durante la visualización, que no tiene ningún efecto a menos que use la opción ZEROFILL.

+6

Muchas gracias por la explicación detallada. Además de solucionar un problema, también aprendí algo valioso. – CodeVirtuoso

+1

Esa es una consulta ordenada, ¡gracias por compartir! – yekta

+0

Realmente, una consulta muy útil para conocer la longitud a la que se debe establecer el índice. He estado usando esto algunas veces para determinar la mejor duración para un índice. ¡Gracias por compartir! –

17

Este error significa que la longitud del índice index es más de 1000 bytes. MySQL y los motores de almacenamiento pueden tener esta restricción. Tengo un error similar en MySQL 5.5 - 'La clave especificada era demasiado larga; max longitud de la clave es 3072 bytes' cuando se ejecuta este script:

CREATE TABLE IF NOT EXISTS test_table1 (
    column1 varchar(500) NOT NULL, 
    column2 varchar(500) NOT NULL, 
    column3 varchar(500) NOT NULL, 
    column4 varchar(500) NOT NULL, 
    column5 varchar(500) NOT NULL, 
    column6 varchar(500) NOT NULL, 
    KEY `index` (column1, column2, column3, column4, column5, column6) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

UTF8 es multi-bytes, y la longitud de la clave se calcula de esta manera - 500 * 3 * 6 = 9000 bytes.

¡Pero tenga en cuenta que la siguiente consulta funciona!

CREATE TABLE IF NOT EXISTS test_table1 (
    column1 varchar(500) NOT NULL, 
    column2 varchar(500) NOT NULL, 
    column3 varchar(500) NOT NULL, 
    column4 varchar(500) NOT NULL, 
    column5 varchar(500) NOT NULL, 
    column6 varchar(500) NOT NULL, 
    KEY `index` (column1, column2, column3, column4, column5, column6) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

... porque yo solía charset = latin1, en este caso la longitud de clave es 500 * 6 = 3000 bytes.

+4

Gracias por responder, esto funciona, pero a costa de renunciar a utf8 charset. ¿Se puede superar de alguna manera esta restricción (tengo acceso completo al servidor), está ahí por una buena razón? – CodeVirtuoso

2

Este límite de tamaño de índice parece ser mayor en las compilaciones de 64 bits de MySQL.

Estaba llegando a esta limitación al intentar volcar nuestra base de datos de desarrollo y cargarla en una VMWare virt local. Finalmente me di cuenta de que el servidor de desarrollo remoto era de 64 bits y que había creado un virt de 32 bits. Acabo de crear un virt de 64 bits y pude cargar la base de datos localmente.

5

ejecutar esta consulta antes de crear o modificar la tabla.

SET @@global.innodb_large_prefix = 1;

esto establecerá longitud de clave max a 3072 bytes

1

acabo de hacer derivación este error con sólo cambiar los valores de la "longitud" en la base de datos original con el total de alrededor de "1000 "cambiando su estructura y exportándola al servidor". :)

Cuestiones relacionadas