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

563

Lorsque 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)que ne nécessite que 21 octets alors que varchar(500)ne nécessite que 501 octets. Ainsi, le nombre total d'octets est de 522, moins de 767. Alors pourquoi ai-je reçu le message d'erreur?

#1071 - Specified key was too long; max key length is 767 bytes
Steven
la source
5
Parce que ce ne sont pas 520 octets, mais plutôt 2080 octets, ce qui dépasse de loin 767 octets, vous pouvez faire colonne1 varchar (20) et colonne2 varchar (170). si vous voulez un caractère / octet équivalent, utilisez latin1
Rahly
3
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
missovic10
3
mysql> sélectionnez maxlen, character_set_name dans information_schema.character_sets où character_set_name in ('latin1', 'utf8', 'utf8mb4'); maxlen | nom_ensemble de caractères ------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4
missovic10
15
'si vous voulez un caractère / octet équivalent, utilisez latin1' Veuillez ne pas le faire . Latin1 est vraiment, vraiment nul. Vous le regretterez.
Stijn de Witt
Référez stackoverflow.com/a/52778785/2137210 pour la solution
Pratik

Réponses:

490

767 octets est la limitation de préfixe indiquée pour les tables InnoDB dans MySQL version 5.6 (et les versions antérieures). C'est 1000 octets de long pour les tables MyISAM. Dans MySQL version 5.7 et supérieure, cette limite a été augmentée à 3072 octets.

Vous devez également savoir que si vous définissez un index sur un grand champ char ou varchar codé en utf8mb4, vous devez diviser la longueur maximale du préfixe d'index de 767 octets (ou 3072 octets) par 4, ce qui donne 191. En effet, la longueur maximale d'un caractère utf8mb4 est de quatre octets. Pour un caractère utf8, ce serait trois octets résultant en une longueur maximale de préfixe d'index de 254.

Une option que vous avez consiste simplement à placer une limite inférieure sur vos champs VARCHAR.

Une autre option (selon la réponse à ce problème ) est d'obtenir le sous-ensemble de la colonne plutôt que le montant total, c'est-à-dire:

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

Ajustez au besoin pour obtenir la clé à appliquer, mais je me demande si cela vaut la peine de revoir votre modèle de données concernant cette entité pour voir s'il y a des améliorations qui vous permettraient de mettre en œuvre les règles métier prévues sans atteindre la limitation MySQL.

Poneys OMG
la source
4
À appliquer en spécifiant un sous-ensemble de la colonne plutôt que le montant entier. Une bonne solution.
Steven
204
Cela n'explique pas pourquoi les champs bien en dessous de la limite de longueur dépassent la limite de longueur ...
Cerin
6
J'ai essayé de modifier les informations @Cerin manquantes ci-dessus, qui sont clairement considérées comme manquantes par d'autres, mais elles sont rejetées comme étant plus appropriées en tant que commentaire. Pour ceux qui essaient de comprendre pourquoi 500 + 20> 767, voir le commentaire de Stefan Endrullis sur la réponse de Julien.
Letharion
8
Cela peut être un problème. Par exemple: j'ai le nom de champ (255) et j'ajoute unique à ce champ au nom (191) car j'utilise utf8mb4. Si mon utilisateur ajoute son nom avec «IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs» et l'autre utilisateur ajoute son nom avec ce «IJUE3ump5fiUuCi16jSofYS234KKVKJ Il doit passer la validation et ne pas être bloqué lors de la saisie en double.
vee
28
La limite d'index est de 767 octets , pas de caractères. Et puisque le utf8mb4jeu de caractères de Mysql (que le reste du monde appelle utf8) a besoin (au plus) de 4 octets par caractère, vous ne pouvez indexer que jusqu'à VARCHAR(191). Le utf8jeu de caractères de Mysql (que le reste du monde appelle cassé) a besoin d'au plus 3 octets par caractère, donc si vous utilisez cela (ce que vous ne devriez pas ), vous pouvez indexer jusqu'àVARCHAR(255)
Stijn de Witt
404

Si quelqu'un rencontre des problèmes avec INNODB / Utf-8 pour essayer de mettre un UNIQUEindex sur un VARCHAR(256)champ, basculez-le sur VARCHAR(255). Il semble que 255 soit la limitation.

PinkTurtle
la source
247
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, votre longueur de clé est limitée à 255 caractères, depuis 3*255 = 765 < 767.
Stefan Endrullis
10
Cela m'a évité beaucoup de frustration - merci. Cela devrait être la réponse acceptée IMO, étant donné que l'utilisateur utilise InnoDB en affirmant qu'il a atteint une limitation 767b.
TheCarver
8
Comme Stefan Endrullis l'a déclaré, cela dépend du jeu de caractères. Si vous utilisez UTF8 qui utilise 3 octets: 255x3 = 765 qui est inférieur à la limite de 767, tandis que 256x3 = 768 qui est supérieur. Mais si vous utilisez UTF8mb4, son 255 * 4 = 1020, donc ce n'est pas vraiment une solution
bernhardh
25
Cette réponse est correcte. Cependant, si 255 fonctionne effectivement pour vous, cela signifie que vous utilisez Mysql utf8, qui est malheureusement cassé. Il ne peut encoder que des caractères dans le plan multilingue de base. Vous obtiendrez des problèmes avec des personnages en dehors de cela. Par exemple, les personnages Emoji qu'ils ont ajoutés tombent en dehors de cela, je pense. Donc, au lieu de basculer vers VARCHAR(255), basculez vers VARCHAR(191) et basculez l'encodage vers utf8mb4(qui est en fait juste utf8, mais MySql voulait rester en arrière. Compat).
Stijn de Witt
1
Pas utile pour ma contrainte unique multicolonne. Cela ne fonctionnerait pas non plus pour la contrainte unique multicolonne de l'OP. (lui donnerait une taille totale de 825 octets)
Barett
352

Lorsque vous atteignez la limite. Réglez les éléments suivants.

  • INNODB utf8 VARCHAR(255)
  • INNODB utf8mb4 VARCHAR(191)
Aley
la source
34
C'est la meilleure réponse. Simple, direct et inclut également utf8mb4limit (qui est l'encodage le plus utilisé pour les bases de données plus récentes, car il accepte les emojis / etc).
Claudio Holanda
10
parce que 767/4 ~ = 191, et 767/3 ~ = 255
Comptable م
11
où et comment le régler?
Dinesh Sunny
1
Oui, en précisant ENGINE=InnoDB DEFAULT CHARSET=utf8à la fin de la CREATE TABLEdéclaration que je pouvais avoir une VARCHAR(255)clé primaire. Merci.
xonya
1
quelqu'un lui donne +1 pour dépasser la limite 191 :)
cagcak
147

MySQL suppose le pire des 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 car cet encodage ne permet pas les caractères au-delà U+FFFF. Pour l'encodage 'utf8mb4' de MySQL, c'est 4 octets par caractère, car c'est ce que MySQL appelle le vrai UTF-8.

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

morganwahl
la source
4
- Ce qui signifie sans doute que lorsque j'utilise utf8mb4, je dois les définir sur (au plus) 191 comme 191 * 4 = 764 <767.
Isaac
2
@Isaac Oui, exactement,
morganwahl
2
Je pense que cela pourrait être la bonne réponse, mais pourriez-vous nous expliquer ce qu'il faudrait faire pour corriger un tel problème? Au moins pour les noobs MySQL comme moi?
Adam Grant
Il n'y a pas qu'une seule façon de contourner cette limite d'index. La question ici concerne les contraintes uniques; pour ceux-ci, vous pouvez avoir une colonne de texte de longueur illimitée, et une autre où vous stockez un hachage (comme MD5) de ce texte, et utilisez la colonne de hachage pour votre contrainte unique. Vous devrez vous assurer que votre programme garde les hachages à jour lorsqu'il modifie le texte, mais il existe différentes façons de gérer cela sans trop de problèmes. Franchement, MySQL devrait implémenter une telle chose lui-même pour que vous n'ayez pas à le faire; Je ne serais pas surpris si MariaDB a quelque chose comme ça intégré.
morganwahl
Un index unique sur une très longue colonne varchar est rare. Réfléchissez à la raison pour laquelle vous en avez besoin, car il peut s'agir d'un problème de conception. Si vous voulez juste un index sur celui-ci pour la recherche, considérez un champ de «mots clés» qui peut contenir 191 caractères, ou divisez le texte en une courte description et un texte long / complet, etc. comme Apache Lucene.
Stijn de Witt
56

exécutez cette requête avant votre requête:

SET @@global.innodb_large_prefix = 1;

cela augmentera la limite à 3072 bytes.

Raza Ahmed
la source
4
Y a-t-il un inconvénient à passer à innodb_large_prefix à l'échelle mondiale? Et cette base de données est-elle "globale" ou toutes les bases de données TOTALEMENT GLOBALES?
SciPhi
5
S'applique uniquement lors de l'utilisation de formats de ligne non standard. Voir dev.mysql.com/doc/refman/5.5/en/… . Plus précisément, "Activez cette option pour autoriser les préfixes de clé d'index de plus de 767 octets (jusqu'à 3072 octets), pour les tables InnoDB qui utilisent les formats de ligne DYNAMIC et COMPRESSED." Le format de ligne par défaut n'est pas affecté.
Chris Lear
5
Cela a bien fonctionné pour moi - plus de détails et un guide peuvent être trouvés ici: mechanics.flite.com/blog/2014/07/29/…
cwd
1
avons-nous besoin de redémarrer le serveur mysql après cela?
SimpleGuy
7
Détails importants manquants de cette réponse. innodb_file_formatdoit être BARRACUDAet Au niveau de la table, vous devez utiliser ROW_FORMAT=DYNAMICou ROW_FORMAT=COMPRESSED. Voir le commentaire de @ cwd ci-dessus avec le guide.
q0rban
46

Solution pour Laravel Framework

Selon la documentation Laravel 5.4. * ; Vous devez définir la longueur de chaîne par défaut dans la bootméthode du app/Providers/AppServiceProvider.phpfichier comme suit:

use Illuminate\Support\Facades\Schema;

public function boot() 
{
    Schema::defaultStringLength(191); 
}

Explication de ce correctif, fournie par la documentation Laravel 5.4. * :

Laravel utilise le utf8mb4jeu de caractères par défaut, qui inclut la prise en charge du stockage des "emojis" dans la base de données. Si vous exécutez une version de MySQL antérieure à la version 5.7.7 ou MariaDB antérieure à la version 10.2.2, vous devrez peut-être configurer manuellement la longueur de chaîne par défaut générée par les migrations afin que MySQL crée des index pour eux. Vous pouvez configurer cela en appelant la Schema::defaultStringLengthméthode dans votreAppServiceProvider .

Alternativement, vous pouvez activer l' innodb_large_prefixoption pour votre base de données. Reportez-vous à la documentation de votre base de données pour savoir comment activer correctement cette option.

Ali Shaukat
la source
10
@BojanPetkovic et je viens juste d'un problème avec Laravel, et cette réponse a en fait résolu mon problème.
mkmnstr
Cette réponse est excellente. Mais quelqu'un sait-il pourquoi cela fonctionne exactement?
UeliDeSchwert
1
La documentation de @Bobby Laravel donne son explication dans la rubrique "Index Lengths & MySQL / MariaDB" laravel.com/docs/5.4/migrations#creating-indexes
Ali Shaukat
1
@Bobby J'ai mis à jour la réponse. J'ai ajouté l'explication donnée par la documentation laravel pour ce correctif.
Ali Shaukat
39

Quel encodage de caractères utilisez-vous? Certains jeux de caractères (comme UTF-16, et cetera) utilisent plus d'un octet par caractère.

ambre
la source
8
Si c'est UTF8, un caractère peut utiliser jusqu'à 4 octets, de sorte que la colonne de 20 caractères est en 20 * 4 + 1octets et la colonne de 500 caractères en 500 * 4 + 2octets
Thanatos
5
Pour ce que ça vaut, j'ai juste eu le même problème et le passage de utf8_general_ci à utf8_unicode_ci a résolu le problème pour moi. Je ne sais pas pourquoi cependant :(
Andresch Serj
11
Pour une VARCHAR(256)colonne avec un UNIQUEindex, le changement de classement n'a eu aucun effet pour moi, comme il l'a fait pour @Andresch. Cependant, la réduction de la longueur de 256 à 255 l'a résolu. Je ne comprends pas pourquoi, car 767 / max 4 octets par caractère donneraient un maximum de 191?
Arjan
10
255*3 = 765; 256*3 = 768. Il semble que votre serveur suppose 3 octets par caractère, @Arjan
Amber
21
@Greg: Vous avez raison, mais cela devrait être élaboré: UTF-8 lui-même utilise 1 à 4 octets par point de code. Les "jeux de caractères" de MySQL (vraiment des encodages) ont un jeu de caractères appelé "utf8" qui est capable de coder une partie de l'UTF-8, et utilise 1 à 3 octets par point de code, et est incapable de coder des points de code en dehors du BMP. Il comprend également un autre jeu de caractères appelé "utf8mb4", qui utilise 1 à 4 octets par point de code et est capable de coder tous les points de code Unicode. (utf8mb4 est UTF-8, utf8 est une version bizarre d'UTF-8.)
Thanatos
28

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

UTF8 nécessite 3 octets par caractère pour stocker la chaîne, donc dans votre cas 20 + 500 caractères = 20 * 3 + 500 * 3 = 1560 octets, ce qui est plus que autorisé 767 octets.

La limite pour UTF8 est de 767/3 = 255 caractères , pour UTF8mb4 qui utilise 4 octets par caractère, elle est de 767/4 = 191 caractères.


Il existe deux solutions à ce problème si vous devez utiliser une colonne plus longue que la limite:

  1. Utilisez un encodage "moins cher" (celui qui nécessite moins d'octets par caractère)
    Dans mon cas, je devais ajouter un index unique sur la colonne contenant la chaîne d'article SEO, car j'utilise uniquement des [A-z0-9\-]caractères pour le référencement, j'ai utilisélatin1_general_ci qui n'utilise qu'un octet par caractère et ainsi la colonne peut avoir une longueur de 767 octets.
  2. Créez un hachage à partir de votre colonne et utilisez un index unique uniquement sur celui-ci.
    L'autre option pour moi était de créer une autre colonne qui stockerait le hachage du référencement, cette colonne aurait la UNIQUEclé pour garantir que les valeurs du référencement sont uniques. J'ajouterais également un KEYindex à la colonne SEO d'origine pour accélérer la recherche.
Buksy
la source
Cela a fait l'affaire. J'ai eu varchar (256) et j'ai dû le changer en varchar (250).
MaRmAR
25

De nombreux utilisateurs ont déjà répondu à la raison pour laquelle vous obtenez un message d'erreur. Ma réponse est de savoir comment le réparer et l'utiliser tel quel.

Référez-vous à partir de ce lien .

  1. Ouvrez le client MySQL (ou client MariaDB). Il s'agit d'un outil en ligne de commande.
  2. Il vous demandera votre mot de passe, entrez votre mot de passe correct.
  3. Sélectionnez votre base de données à l'aide de cette commande use my_database_name;

Base de données modifiée

  1. set global innodb_large_prefix=on;

Requête OK, 0 lignes affectées (0,00 sec)

  1. set global innodb_file_format=Barracuda;

Requête OK, 0 lignes affectées (0,02 sec)

  1. Accédez à votre base de données sur phpMyAdmin ou quelque chose comme ça pour une gestion facile. > Sélectionner la base de données> Afficher la structure de la table > Aller à l' onglet Opérations . > Changez ROW_FORMAT en DYNAMIC et enregistrez les modifications.
  2. Accédez à l' onglet de structure du tableau > Cliquez sur Unique bouton .
  3. Terminé. Maintenant, il ne devrait pas avoir d'erreurs.

Le problème de ce correctif est que si vous exportez db vers un autre serveur (par exemple de l'hôte local vers l'hôte réel) et que vous ne pouvez pas utiliser la ligne de commande MySQL sur ce serveur. Vous ne pouvez pas le faire fonctionner là-bas.

vee
la source
si vous êtes toujours en erreur après avoir saisi la requête ci-dessus, essayez d'aller dans "phpmyadmin"> définissez le "classement" selon vos préférences (pour moi, j'utilise "utf8_general_ci")> cliquez sur appliquer (même si c'est déjà utf8)
Anthony Kal
Je n'utilise pas un outil qui fonctionne avec vos instructions, mais je vote toujours pour essayer d'aider les gens à résoudre le problème. Il existe une infinité d'explications sur les causes du problème, mais remarquablement peu sur la manière de le résoudre.
Teekin
20
Specified key was too long; max key length is 767 bytes

Vous avez reçu ce message car 1 octet équivaut à 1 caractère uniquement si vous utilisez le latin-1jeu de caractères. Si vous utilisez utf8, chaque caractère sera considéré comme 3 octets lors de la définition de votre colonne clé. Si vous utilisez utf8mb4, chaque caractère sera considéré comme 4 octets lors de la définition de votre colonne clé. Ainsi, vous devez multiplier la limite de caractères de votre champ clé par 1, 3 ou 4 (dans mon exemple) pour déterminer le nombre d'octets que le champ clé essaie d'autoriser. Si vous utilisez uft8mb4, vous ne pouvez définir que 191 caractères pour un champ de clé primaire native, InnoDB. Il suffit de ne pas violer 767 octets.

Anthony Rutledge
la source
17

Remplacez utf8mb4par utf8dans votre fichier d'importation.

entrez la description de l'image ici

Bryan
la source
Pourquoi doit-on faire exactement cela? De plus, si cela a des inconvénients (ce que je suppose), vous devez le mentionner
Nico Haase
16

vous pouvez ajouter une colonne du md5 de longues colonnes

bricolage
la source
Notez que cela ne vous permettra pas d'effectuer des analyses de plage sur ces colonnes. Les longueurs de préfixe sur les VARCHAR vous permettront de conserver cette caractéristique, tout en provoquant des correspondances potentiellement fausses dans l'index (et la recherche et la recherche de lignes 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 prend pas en charge avec les tables InnoDB.)
Thanatos
Je ne pouvais pas utiliser d'index de préfixe car j'avais besoin de maintenir la compatibilité avec H2 à des fins de test et j'ai trouvé que l'utilisation d'une colonne de hachage fonctionnait bien. Je recommanderais fortement 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 fuir des données si l'une de vos requêtes vérifie uniquement la valeur de hachage, et non la valeur de colonne complète.
Little Mike
13

Nous avons rencontré ce problème lors de la tentative d'ajout d'un index UNIQUE à un champ VARCHAR (255) à l'aide de utf8mb4. Bien que le problème soit déjà bien décrit ici, je voulais ajouter quelques conseils pratiques sur la façon dont nous avons compris cela et l'avons résolu.

Lors de l'utilisation de utf8mb4, les caractères comptent pour 4 octets, alors que sous utf8, ils peuvent l'être pour 3 octets. Les bases de données InnoDB ont une limite selon laquelle les index ne peuvent contenir que 767 octets. Ainsi, lorsque vous utilisez utf8, vous pouvez stocker 255 caractères (767/3 = 255), mais en utilisant utf8mb4, vous ne pouvez stocker que 191 caractères (767/4 = 191).

Vous pouvez absolument ajouter des index réguliers pour les VARCHAR(255)champs en utilisant utf8mb4, mais ce qui se passe, c'est que la taille de l'index est tronquée automatiquement à 191 caractères - comme unique_keyici:

Capture d'écran de Sequel Pro montrant un index tronqué à 191 caractères

C'est très bien, car les index réguliers sont juste utilisés pour aider MySQL à rechercher plus rapidement dans vos données. Le champ entier n'a pas besoin d'être indexé.

Alors, pourquoi MySQL tronque-t-il automatiquement l'index pour les index réguliers, mais renvoie-t-il une erreur explicite lorsque vous essayez de le faire pour les index uniques? Eh bien, pour que MySQL puisse déterminer si la valeur insérée ou mise à jour existe déjà, il doit réellement indexer la valeur entière et pas seulement une partie.

À la fin de la journée, si vous souhaitez avoir un index unique sur un champ, tout le contenu du champ doit tenir dans l'index. Pour utf8mb4, cela signifie réduire la longueur des champs VARCHAR à 191 caractères ou moins. Si vous n'avez pas besoin d'utf8mb4 pour cette table ou ce champ, vous pouvez le redéposer vers utf8 et conserver vos 255 champs de longueur.

maknz
la source
11

Voici ma réponse originale:

Je laisse simplement tomber la base de données et recrée comme ceci, et l'erreur a disparu:

drop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;

Cependant, cela ne fonctionne pas pour tous les cas.

Il s'agit en fait d'un problème d'utilisation d'index sur les colonnes VARCHAR avec le jeu de caractères utf8(ou utf8mb4), avec les colonnes VARCHAR qui ont plus d'une certaine longueur de caractères. Dans le cas deutf8mb4 , cette certaine longueur est de 191.

Veuillez consulter la section Index long de cet article pour plus d'informations sur l'utilisation des index longs dans la base de données MySQL: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- jeu de caractères-à-utf8mb4

Châu Hồng Lĩnh
la source
Résolu le problème pour la configuration openmeetings (BTW vous avez sauvé ma nuit :-)
Ludo
11

5 solutions:

La limite a été relevée en 5.7.7 (MariaDB 10.2.2?). Et il peut être augmenté avec un peu de travail en 5.6 (10.1).

Si vous atteignez la limite parce que vous essayez d'utiliser CHARACTER SET utf8mb4. Effectuez ensuite l'une des opérations suivantes (chacune présente un inconvénient) pour éviter l'erreur:

  Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
  Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
  ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
  Use a "prefix" index -- you lose some of the performance benefits.
  Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;  -- (or COMPRESSED)

- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes

Rick James
la source
10

J'ai résolu ce problème avec:

varchar(200) 

remplacé par

varchar(191)

tous les varchar qui en ont plus de 200 les remplacent par 191 ou leur mettent du texte.

flik
la source
C'est aussi ce qui a fonctionné pour moi. J'ai eu un varchar (250), mais les données n'ont jamais été aussi longues. Changé en varchar (100). Merci pour l'idée :)
Arun Basil Lal
7

J'ai fait quelques recherches sur ce sujet, j'ai finalement obtenu des modifications personnalisées

Pour MySQL Workbench 6.3.7 Version L'inter phase graphique est disponible

  1. Démarrez Workbench et sélectionnez la connexion.
  2. Accédez à la gestion ou à l'instance et sélectionnez Fichier d'options.
  3. Si Workbench vous demande l'autorisation de lire le fichier de configuration, puis l'autorisez en appuyant deux fois sur OK.
  4. Au centre, la fenêtre du fichier d'options administrateur s'affiche.
  5. Allez sur l'onglet InnoDB et vérifiez le innodb_large_prefix s'il n'est pas coché dans la section Général.
  6. définissez la valeur de l'option innodb_default_row_format sur DYNAMIC.

Pour les versions inférieures à 6.3.7, les options directes ne sont pas disponibles, il faut donc aller avec l'invite de commande

  1. Démarrez CMD en tant qu'administrateur.
  2. Aller au directeur où le serveur mysql est installé La plupart des cas, c'est dans "C: \ Program Files \ MySQL \ MySQL Server 5.7 \ bin", donc la commande est "cd \" "cd Program Files \ MySQL \ MySQL Server 5.7 \ bin".
  3. Maintenant, exécutez la commande mysql -u nom_utilisateur -p databasecheema Maintenant, il a demandé le mot de passe de l'utilisateur respectif. Fournissez le mot de passe et entrez dans l'invite mysql.
  4. Nous devons définir certains paramètres globaux entrer les commandes ci-dessous un par un ensemble global innodb_large_prefix = on; set global innodb_file_format = barracuda; set global innodb_file_per_table = true;
  5. Maintenant, nous devons enfin modifier le ROW_FORMAT de la table requise par défaut son COMPACT, nous devons le définir sur DYNAMIC.
  6. utilisez la commande suivante alter table nom_table ROW_FORMAT = DYNAMIC;
  7. Terminé
Abhishek
la source
Je ne trouve pas ceci: 6. définissez la valeur de l'option innodb_default_row_format sur DYNAMIC.
Adrian Cid Almaguer
si j'utilise set global innodb_default_row_format = DYNAMIC;je vois ce message: ERREUR 1193 (HY000): variable système inconnue 'innodb_default_row_format'
Adrian Cid Almaguer
comment vous avez obtenu une erreur de l'établi à cmd? Je l'ai fait depuis l'établi, il a directement l'option.
Abhishek
Je le fais depuis CMD parce que je ne vois pas l'option dans Workbench
Adrian Cid Almaguer
1
Je vois le problème que cette var a été introduite dans la v5.7.9 et j'ai la version v5.6.33, merci
Adrian Cid Almaguer
7

Pour laravel 5.7 à 6.0

Étapes à suivre

  1. Allez à App\Providers\AppServiceProvider.php.
  2. Ajoutez ceci au fournisseur use Illuminate\Support\Facades\Schema;en haut.
  3. A l'intérieur de la fonction de démarrage Ajouter ceci Schema::defaultStringLength(191);

que tout, profitez-en.

Manojkiran.A
la source
A également fonctionné pour Laravel 5.8.
Neo
C'est une mauvaise solution. Raison: les index ne sont pas censés être infiniment longs. Lorsque vous appliquez un index unique à quelque chose, vous souhaitez que l'index soit fixe avec la plupart du temps. Cela signifie que vous NE DEVRIEZ PAS faire des choses comme emailuniques, mais vous devez hacher l'e-mail et les rendre uniques. Contrairement aux données de chaîne brutes, les hachages ont une largeur fixe et peuvent être indexés et rendus uniques sans problème. Au lieu de comprendre le problème, vous répandez des pratiques horribles qui ne sont pas à l'échelle.
NB
5

changez votre classement. Vous pouvez utiliser utf8_general_ci qui prend en charge presque tous

Nids Barthwal
la source
"Presque" est un assez bon indice que ce n'est pas une solution à long terme
Nico Haase
4

Le simple fait de passer utf8mb4à la utf8création de tableaux a résolu mon problème. Par exemple: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;à CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;.

MajidJafari
la source
4

Pour résoudre ce problème, cela fonctionne pour moi comme un charme.

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
Nick Pridorozhko
la source
Je confirme que mon problème était également le classement de la base de données. Je n'ai aucune explication. J'utilise mysql v5.6.32 et le classement DB était utf8mb4_unicode_ci.
mahyard
2

Sur la base de la colonne ci-dessous, ces 2 colonnes de chaînes variables utilisent le utf8_general_ciclassement (le utf8jeu de caractères est implicite).

Dans MySQL, utf8charset utilise un maximum de 3 octets pour chaque caractère. Ainsi, il devrait allouer 500 * 3 = 1500 octets, ce qui est beaucoup plus important que les 767 octets autorisés par MySQL. C'est pourquoi vous obtenez cette erreur 1071.

En d'autres termes, vous devez calculer le nombre de caractères en fonction de la représentation des octets du jeu de caractères car tous les jeux de caractères ne sont pas une représentation à un seul octet (comme vous le supposiez.) IE utf8dans MySQL utilise au plus 3 octets par caractère, 767 / 3≈255 caractères et, pour utf8mb4une représentation d'au plus 4 octets, 767 / 4≈191 caractères.

Il est également connu que MySQL

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci
Devy
la source
1

J'ai trouvé cette requête utile pour détecter les colonnes dont l'index violait la longueur maximale:

SELECT
  c.TABLE_NAME As TableName,
  c.COLUMN_NAME AS ColumnName,
  c.DATA_TYPE AS DataType,
  c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
  s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
  ON s.table_name = c.TABLE_NAME
 AND s.COLUMN_NAME = c.COLUMN_NAME 
WHERE c.TABLE_SCHEMA = DATABASE()
  AND c.CHARACTER_MAXIMUM_LENGTH > 191 
  AND c.DATA_TYPE IN ('char', 'varchar', 'text')
Andrew
la source
1

Veuillez vérifier si sql_modec'est comme

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

si c'est le cas, passez à

sql_mode=NO_ENGINE_SUBSTITUTION

OU

redémarrez votre serveur en changeant votre fichier my.cnf (en mettant ce qui suit)

innodb_large_prefix=on
neel
la source
1

Dans mon cas, j'ai eu ce problème lorsque je sauvegardais une base de données en utilisant les caractères de sortie / entrée de redirection linux. Par conséquent, je change la syntaxe comme décrit ci-dessous. PS: en utilisant un terminal linux ou mac.

Sauvegarde (sans la> redirection)

# mysqldump -u root -p databasename -r bkp.sql

Restaurer (sans la <redirection)

# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql

L'erreur "La clé spécifiée était trop longue; la longueur maximale de la clé est de 767 octets" a simplement disparu.

Cassio Seffrin
la source
1

Longueurs d'index et MySQL / MariaDB


Laravel utilise le jeu de caractères utf8mb4 par défaut, qui inclut la prise en charge du stockage des "emojis" dans la base de données. Si vous exécutez une version de MySQL antérieure à la version 5.7.7 ou MariaDB antérieure à la version 10.2.2, vous devrez peut-être configurer manuellement la longueur de chaîne par défaut générée par les migrations afin que MySQL crée des index pour eux. Vous pouvez configurer cela en appelant la méthode Schema :: defaultStringLength dans votre AppServiceProvider:

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

Vous pouvez également activer l'option innodb_large_prefix pour votre base de données. Reportez-vous à la documentation de votre base de données pour savoir comment activer correctement cette option.

Référence du blog: https://www.scratchcode.io/specified-key-too-long-error-in-laravel/

Référence de la documentation officielle de laravel: https://laravel.com/docs/5.7/migrations

Mayank Dudakiya
la source
0

Si vous créez quelque chose comme:

CREATE TABLE IF NOT EXISTS your_table (
  id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(256) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

ça devrait être quelque chose comme

CREATE TABLE IF NOT EXISTS your_table (
      id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
      name varchar(256) COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

mais vous devez vérifier l'unicité de cette colonne à partir du code ou ajouter une nouvelle colonne en tant que MD5 ou SHA1 de la colonne varchar

10undertiber
la source
3
Ensuite, votre clé unique a été perdue. Je pense que la meilleure façon est simplement de réduire la longueur du nom à 191.
haudoing
1
Pourquoi vérifier l'unicité par programme s'il s'agit d'une fonctionnalité de base de données native?
Paweł Tomkiel
0

En raison des limitations de préfixe, cette erreur se produira. 767 octets est la limitation de préfixe indiquée pour les tables InnoDB dans les versions MySQL antérieures à 5.7. C'est 1000 octets de long pour les tables MyISAM. Dans MySQL version 5.7 et supérieure, cette limite a été augmentée à 3072 octets.

L'exécution de ce qui suit sur le service vous donnant l'erreur devrait résoudre votre problème. Cela doit être exécuté dans la CLI MYSQL.

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;
Rivières
la source
-1

Remplacez CHARSET du champ d'indexation par "latin1",
c'est-à-dire ALTER TABLE tbl CHANGE myfield myfield varchar (600) CHARACTER SET latin1 DEFAULT NULL;
latin1 prend un octet pour un caractère au lieu de quatre

Stan Holodnak
la source
5
Et s'il essayait d'insérer des caractères non latins1 ?
Paweł Tomkiel
4
C'est la pire chose à faire. Ne fais jamais cela.
Sebas
1
dans mon cas, c'est sur une colonne qui stocke les noms de chemin avec seulement des caractères hexadécimaux ... donc cela pourrait être une solution pour quelqu'un. cela dépend vraiment de ce que vous voulez stocker ...
codewandler
J'ai dû déprécier cela, car l'utilisation de latin1 n'est pas une solution en 2016AD. J'ai encore des cauchemars horribles sur le temps que nous avons dû convertir une base de données de latin1 en utf8 en 2007. Ugh. Pas beau. Du tout.
Bet Lamed
J'ai eu le même problème sur un index unique sur deux colonnes où je stocke les adresses bitcoin et les ID de transaction. Ce seront toujours des caractères ASCII, donc j'utiliserai latin1 sur ces colonnes. Upvoting.
alexg
-2

Si vous avez changé innodb_log_file_sizerécemment, essayez de restaurer la valeur précédente qui fonctionnait.

AnkitK
la source