web-dev-qa-db-fra.com

# 1071 - La clé spécifiée était trop longue. La longueur maximale de la clé est de 1000 octets.

Je sais que les questions portant sur ce titre ont déjà reçu une réponse, mais veuillez continuer à lire. J'ai lu attentivement toutes les autres questions/réponses sur cette erreur avant de poster.

Je reçois l'erreur ci-dessus pour la requête suivante:

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;

Quelqu'un at-il une idée pourquoi et comment résoudre ce problème? Le problème est que cette même requête fonctionne parfaitement sur mon ordinateur local et fonctionne également sur mon hôte précédent. Btw.it est issu d'un projet mature - phpdevshell - alors je suppose que ces gars-là savent ce qu'ils font, même si on ne sait jamais.

Tout indice apprécié.

J'utilise phpMyAdmin.

81
CodeVirtuoso

Comme @Devart le dit, la longueur totale de votre index est trop longue.

La réponse courte est que vous ne devriez de toute façon pas indexer de telles colonnes VARCHAR, car l'index sera très volumineux et inefficace.

La meilleure pratique consiste à utiliser index de préfixe afin que vous n'indexiez qu'une sous-chaîne de gauche des données. La plupart de vos données seront de toute façon beaucoup plus courtes que 255 caractères.

Vous pouvez déclarer une longueur de préfixe par colonne lorsque vous définissez l'index. Par exemple:

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

Mais quelle est la meilleure longueur de préfixe pour une colonne donnée? Voici une méthode pour le savoir:

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

Il vous indique la proportion de lignes n'ayant pas plus d'une longueur de chaîne donnée dans la colonne menu_link. Vous pourriez voir une sortie comme ceci:

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

Cela vous indique que 80% de vos chaînes comportent moins de 20 caractères et que toutes vos chaînes comportent moins de 50 caractères. Il n’est donc pas nécessaire d’indexer plus d’une longueur de préfixe de 50 ni d’indexer la totalité de la longueur de 255 caractères.

PS: Les types de données INT(1) et INT(32) indiquent un autre malentendu à propos de MySQL. L'argument numérique n'a aucun effet sur le stockage ou la plage de valeurs autorisée pour la colonne. INT a toujours 4 octets et autorise toujours les valeurs comprises entre -2147483648 et 2147483647. L'argument numérique concerne les valeurs de remplissage lors de l'affichage, ce qui n'a d'effet que si vous utilisez l'option ZEROFILL.

136
Bill Karwin

Cette erreur signifie que la longueur de l'index index est supérieure à 1000 octets. MySQL et les moteurs de stockage peuvent avoir cette restriction. J'ai une erreur similaire sur MySQL 5.5 - 'La clé spécifiée était trop longue; La longueur maximale de la clé est de 3072 octets 'lors de l'exécution de ce 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 est composé de plusieurs octets et la longueur de la clé est calculée de la manière suivante: 500 * 3 * 6 = 9 000 octets.

Mais remarquez, la requête suivante fonctionne!

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;

... parce que j'ai utilisé CHARSET = latin1, dans ce cas, la longueur de la clé est de 500 * 6 = 3000 octets.

26
Devart

lancez cette requête avant de créer ou de modifier une table.

SET @@global.innodb_large_prefix = 1;

cela va définir la longueur maximale de la clé à 3072 octets

9
Raza Ahmed

J'ai eu ce problème, et résolu en suivant:

Cause

Il existe un bogue connu avec MySQL lié à MyISAM, au jeu de caractères UTF8 et aux index que vous pouvez vérifier ici.

Résolution

  • Assurez-vous que MySQL est configuré avec le moteur de stockage InnoDB.

  • Changez le moteur de stockage utilisé par défaut pour que les nouvelles tables soient toujours créées correctement:

    set GLOBAL storage_engine='InnoDb';

  • Pour MySQL 5.6 et versions ultérieures, utilisez les éléments suivants:

    SET GLOBAL default_storage_engine = 'InnoDB';

  • Enfin, assurez-vous de suivre les instructions fournies dans Migration vers MySQL .

référence

6
Vishrant

Cette limite de taille d'index semble être plus grande sur les versions 64 bits de MySQL.

J'avais atteint cette limite en essayant de vider notre base de données dev et de la charger sur un ordinateur virtuel VMWare local. Finalement, j'ai réalisé que le serveur de développement distant était en 64 bits et que j'avais créé un logiciel virtuel 32 bits. Je viens de créer un virt 64 bits et j'ai pu charger la base de données localement.

3
Ryan Olson

Je viens de faire contourner cette erreur en modifiant simplement les valeurs de la "longueur" dans la base de données d'origine pour un total d'environ "1000" en modifiant sa structure, puis en exportant la même chose vers le serveur. :)

2
Vishwadeep Kapoor

Je faisais face au même problème, utilisé ci-dessous requête pour le résoudre.

Lors de la création de la base de données, vous pouvez utiliser le codage utf-8.

par exemple. create database my_db character set utf8 collate utf8_bin;

1
Sudhir Dhumal