610 votes

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

Quand j'ai exécuté la commande suivante :

ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);

J'ai reçu ce message d'erreur :

#1071 - Specified key was too long; max key length is 767 bytes

Informations sur la colonne1 et la colonne2 :

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

Je pense varchar(20) ne nécessite que 21 octets, tandis que varchar(500) ne nécessite que 501 octets. Le total des octets est donc de 522, soit moins que 767. Alors pourquoi ai-je reçu le message d'erreur ?

#1071 - Specified key was too long; max key length is 767 bytes

5 votes

Étant donné qu'il ne s'agit pas de 520 octets, mais plutôt de 2080 octets, ce qui dépasse de loin 767 octets, vous pouvez utiliser column1 varchar(20) et column2 varchar(170). Si vous voulez une équivalence caractère/octet, utilisez latin1.

3 votes

Je pense que votre calcul est un peu faux ici. mysql utilise 1 ou 2 octets supplémentaires pour enregistrer la longueur des valeurs : 1 octet si la longueur maximale de la colonne est de 255 octets ou moins, 2 si elle est supérieure à 255 octets. l'encodage utf8_general_ci nécessite 3 octets par caractère, donc varchar(20) utilise 61 octets, varchar(500) utilise 1502 octets au total 1563 octets

3 votes

Mysql> select maxlen, character_set_name from information_schema.character_sets where character_set_name in('latin1', 'utf8', 'utf8mb4') ; maxlen | character_set_name ------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4

548voto

OMG Ponies Points 144785

767 octets, c'est le Limitation du préfixe énoncé pour les tables InnoDB - elle est de 1 000 octets pour les tables MyISAM.

Selon le réponse à cette question vous pouvez obtenir l'application de la clé en spécifiant un sous-ensemble de la colonne plutôt que le montant total. IE :

ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );

Faites les ajustements nécessaires pour que la clé s'applique, mais je me demande si cela ne vaudrait pas la peine de revoir votre modèle de données concernant cette entité pour voir s'il n'y a pas d'améliorations qui vous permettraient de mettre en œuvre les règles commerciales prévues sans vous heurter à la limitation de MySQL.

4 votes

Pour appliquer en spécifiant un sous-ensemble de la colonne plutôt que le montant total. Une bonne solution.

0 votes

@OMGPonies : Savez-vous si DB2/MSSQL/Oracle ont la même limitation sur la taille des index ? Par exemple, HSQL n'a pas une telle limitation...

0 votes

@dma_k : Je n'ai pas d'expérience avec DB2, mais je n'ai pas rencontré ce problème avec SQL Server ou Oracle.

421voto

Julien Points 736

Si quelqu'un a des problèmes avec INNODB / Utf-8 en essayant de mettre un fichier UNIQUE sur un VARCHAR(256) en le commutant sur VARCHAR(255) . Il semble que la limite soit de 255.

255 votes

Le nombre de caractères autorisés dépend simplement de votre jeu de caractères. UTF8 peut utiliser jusqu'à 3 octets par caractère, utf8mb4 jusqu'à 4 octets, et latin1 seulement 1 octet. Ainsi, pour utf8, la longueur de votre clé est limitée à 255 caractères, puisque 3*255 = 765 < 767 .

10 votes

Cela m'a épargné beaucoup de frustration - merci. Ce devrait être la réponse acceptée IMO, considérant que l'utilisateur utilise InnoDB en prétendant qu'il a rencontré une limitation de 767b.

8 votes

Comme Stefan Endrullis l'a dit, cela dépend du jeu de caractères. Si vous utilisez UTF8 qui utilise 3 octets : 255x3=765 ce qui est inférieur à la limite de 767, alors que 256x3=768 ce qui est supérieur. Mais si vous utilisez UTF8mb4, 255*4=1020, ce n'est donc pas une vraie solution.

147voto

morganwahl Points 1

Mysql suppose le pire cas pour le nombre d'octets par caractère dans la chaîne. Pour l'encodage MySQL 'utf8', c'est 3 octets par caractère, puisque cet encodage ne permet pas de caractères au-delà de U+FFFF. Pour l'encodage MySQL 'utf8mb4', c'est 4 octets par caractère, puisque c'est ce que MySQL appelle l'UTF-8 réel.

Donc, en supposant que vous utilisez 'utf8', votre première colonne prendra 60 octets de l'index, et votre seconde 1500.

5 votes

- Ce qui signifie vraisemblablement que lorsque j'utilise utf8mb4, je dois les définir à (au maximum) 191 car 191*4 = 764 < 767.

2 votes

@Isaac Oui, exactement,

2 votes

Je pense que c'est peut-être la bonne réponse, mais pourriez-vous préciser ce qu'il faut faire pour corriger un tel problème ? Au moins pour les novices de MySQL comme moi ?

39voto

Amber Points 159296

Quel est le codage des caractères que vous utilisez ? Certains jeux de caractères (comme UTF-16, etc.) utilisent plus d'un octet par caractère.

8 votes

S'il s'agit d'UTF8, un caractère peut utiliser jusqu'à 4 octets, de sorte que la colonne de 20 caractères est la suivante 20 * 4 + 1 octets, et la colonne de 500 caractères est 500 * 4 + 2 octets

5 votes

Pour ce que ça vaut, je viens d'avoir le même problème et passer de utf8_general_ci à utf8_unicode_ci a résolu le problème pour moi. Je ne sais pas pourquoi cependant :(

11 votes

Pour un VARCHAR(256) avec une colonne UNIQUE le changement de collation n'a eu aucun effet pour moi, comme pour @Andresch. Par contre, la réduction de la longueur de 256 à 255 a résolu le problème. Je ne comprends pas pourquoi, car 767 / max 4 octets par caractère donnerait un maximum de 191 ?

16voto

diyism Points 1191

Vous pourriez ajouter une colonne de la md5 des colonnes longues

0 votes

Notez que cela ne vous permettra pas d'effectuer des analyses de plage sur ces colonnes. Les longueurs de préfixe sur les VARCHARs vous permettront de conserver cette caractéristique, tout en provoquant des correspondances erronées dans l'index (et un balayage et une recherche de ligne pour les éliminer) (voir la réponse acceptée). (Il s'agit essentiellement d'un index de hachage implémenté manuellement, que malheureusement MysQL ne supporte pas avec les tables InnoDB).

0 votes

Je ne pouvais pas utiliser les indices de préfixe car je devais maintenir la compatibilité avec H2 à des fins de test, et j'ai trouvé que l'utilisation d'une colonne de hachage fonctionne bien. Je voudrais fortement recommande d'utiliser une fonction résistante aux collisions telle que SHA1 au lieu de MD5 pour empêcher les utilisateurs malveillants de créer des collisions. Une collision d'index pourrait être exploitée pour faire fuir des données si l'une de vos requêtes ne vérifie que la valeur de hachage, et non la valeur complète de la colonne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X