#1071-la clé spécifiée était trop longue; la longueur maximale de la clé est de 767 octets
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 colonne1 et colonne2:
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
Je pense que varchar(20)
exige seulement 21 octets, tandis que varchar(500)
ne nécessite 501 octets. Donc, 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
27 réponses
767 octets est la limitation de préfixe indiquée pour les tables InnoDB dans la version 5.6 de MySQL (et les versions antérieures). Il fait 1000 octets de long pour les tables MyISAM. Dans la version 5.7 de MySQL et vers le haut, cette limite a été augmentée à 3072 octets.
Vous devez également savoir que si vous définissez un index sur un champ big 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. C'est parce que la longueur maximale d'un le caractère utf8mb4 est de quatre octets. Pour un caractère utf8, il serait de trois octets, ce qui entraînerait une longueur maximale du préfixe d'index de 254.
Une option que vous avez est de simplement placer une limite inférieure sur vos champs VARCHAR.
Une autre option (selon la réponse à ce problème ) consiste à 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) );
Tweak comme vous devez obtenir la clé à appliquer, mais je me demande si cela vaudrait la peine de revoir votre modèle de données à ce sujet entité pour voir s'il existe des améliorations qui vous permettraient d'implémenter les règles métier prévues sans atteindre la limitation MySQL.
Si QUELQU'un a des problèmes avec INNODB / Utf-8 essayant de mettre un index UNIQUE
sur un champ VARCHAR(256)
, Passez-le à VARCHAR(255)
. Il semble que 255 est la limitation.
Lorsque vous atteignez la limite. Définissez les éléments suivants.
- INNODB
utf8
VARCHAR(255)
- INNODB
utf8mb4
VARCHAR(191)
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 puisque cet encodage n'autorise pas les 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 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.
Exécutez cette requête avant votre requête:
SET @@global.innodb_large_prefix = 1;
Cela augmentera la limite à 3072 bytes
.
Quel encodage de caractères Utilisez-vous? Certains jeux de caractères (comme UTF-16, etc.) utilisent plus d'un octet par caractère.
Solution Pour Laravel Cadre
Selon Laravel 5.4.* documentation ; vous devez définir la longueur de chaîne par défaut dans le
Démarrage
Méthode de
App / Fournisseurs / AppServiceProvider.php
Fichier comme suit:
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
Explication de ce correctif, donnée par Laravel 5.4.* documentation;
Laravel utilise le jeu de caractères utf8mb4 par défaut, qui comprend 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 puisse créer des index pour eux. Vous pouvez configurer cela en appelant la méthode Schema::defaultStringLength dans votre AppServiceProvider
Vous pouvez également activer l'option innodb_large_prefix pour votre la base de données. Reportez-vous à la documentation de votre base de données pour obtenir des instructions sur comment activer cette option.
Je pense que varchar (20) ne nécessite que 21 octets alors que varchar (500) seulement nécessite 501 octets. Donc, le nombre total d'octets est de 522, moins de 767. Alors pourquoi je reçois le message d'erreur?
UTF8 nécessite 3 octets par caractère pour stocker la chaîne de caractères, donc dans votre cas 20 + 500 caractères = 20*3+500*3 = 1560 octets qui est plus autorisés 767 octets.
La limite pour UTF8 est 767/3 = 255 caractères , pour UTF8mb4 qui utilise 4 octets par caractère il est 767/4 = 191 caractères.
Il existe deux solutions à ce problème si vous devez utiliser une colonne plus longue que la limite:
-
utilisez un encodage "moins cher "(celui qui nécessite moins d'octets par caractère)
Dans mon cas, j'avais besoin d'ajouter un index Unique sur une colonne contenant une chaîne de référencement d'article, car je n'utilise que des caractères[A-z0-9\-]
pour le référencement, j'ai utilisélatin1_general_ci
qui utilise un seul octet par caractère et donc la colonne peut avoir une longueur de 767 octets. -
créez un hachage à partir de votre colonne et utilisez un index unique uniquement sur
L'autre option pour moi était de créer une autre colonne qui stockerait le hachage du référencement, cette colonne aurait la cléUNIQUE
pour s'assurer que les valeurs de référencement sont uniques. J'ajouterais égalementKEY
index à la colonne de référencement d'origine pour accélérer la recherche.
Specified key was too long; max key length is 767 bytes
Vous avez reçu ce message car 1 octet est égal à 1 caractère uniquement si vous utilisez le jeu de caractères latin-1
. 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 étant de 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é tente d'autoriser. Si vous utilisez uft8mb4, vous ne pouvez définissez 191 caractères pour un champ de clé primaire InnoDB natif. Il suffit de ne pas violer 767 octets.
La réponse sur la raison pour laquelle vous obtenez un message d'erreur a déjà été répondue par de nombreux utilisateurs ici. Ma réponse est sur la façon de le réparer et de l'utiliser tel quel.
Reportez-vous à partir de ce lien.
- Ouvrez le client MySQL (ou le client MariaDB). C'est un outil de ligne de commande.
- il vous demandera votre mot de passe, entrez votre mot de passe correct.
- Sélectionnez votre base de données à l'aide de cette commande
use my_database_name;
Base de données modifiée
set global innodb_large_prefix=on;
Requête OK, 0 lignes affectées (0,00 sec)
set global innodb_file_format=Barracuda;
Requête OK, 0 lignes affectées (0.02 sec)
- Allez dans votre base de données sur phpMyAdmin ou quelque chose comme ça pour une gestion facile. > Sélectionnez base de données > Afficher la table structure > accédez à l'onglet opérations. > Changer ROW_FORMAT à dynamique et enregistrer les modifications.
- Allez dans l'onglet structure de la table > cliquez sur Unique bouton.
- fait. Maintenant, il devrait a pas d'erreurs.
Le problème de ce correctif est si vous exportez la base de données vers un autre serveur (par exemple de localhost à l'hôte réel) et que vous ne pouvez pas utiliser la ligne de commande MySQL sur ce serveur. Vous ne pouvez pas faire le travail.
Nous avons rencontré ce problème en essayant d'ajouter un index UNIQUE à un champ VARCHAR(255) en utilisant 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 l'avons compris et résolu.
Lorsque vous utilisez utf8mb4, les caractères comptent comme 4 octets, alors que sous utf8, ils pourraient être de 3 octets. Les bases de données InnoDB ont une limite que 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 peut stocker que 191 caractères (767/4 = 191).
Vous êtes absolument capable d'ajouter des index réguliers pour les champs VARCHAR(255)
en utilisant utf8mb4, mais ce qui se passe est que la taille de l'index est tronquée à 191 caractères automatiquement-comme unique_key
ici:
C'est bien, car les index réguliers sont simplement utilisés pour aider MySQL à rechercher vos données plus rapidement. Le champ entier n'a pas besoin d'être indexé.
Alors, pourquoi MySQL tronque-t-il automatiquement l'index pour index, mais lancer une erreur explicite en essayant de le faire pour des index uniques? Eh bien, pour que MySQL puisse déterminer si la valeur insérée ou mise à jour existe déjà, il doit effectivement indexer toute la valeur et pas seulement une partie de celle-ci.
À la fin de la journée, si vous voulez avoir un index unique sur un champ, tout le contenu du champ doit tenir dans l'index. Pour utf8mb4, cela signifie réduire vos longueurs de champ VARCHAR à 191 caractères ou moins. Si vous n'avez pas besoin d'utf8mb4 pour cette table ou ce champ, vous pouvez le déposer en utf8 et pouvoir conserver vos 255 champs de longueur.
Voici ma réponse originale:
Je viens de laisser tomber la base de données et de recréer comme ceci, et l'erreur est partie:
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.
C'est en fait un problème d'utilisation d'index sur les colonnes VARCHAR avec le jeu de caractères utf8
(ou utf8mb4
), avec des colonnes VARCHAR qui ont plus d'une certaine longueur de caractères. Dans le cas de utf8mb4
, Cette certaine longueur est 191.
Veuillez vous référer à la section index Long dans 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-character-set-to-utf8mb4
J'ai fait une recherche sur ce sujet a finalement obtenu un changement personnalisé
Pour MySQL workbench 6.3.7 Version Graphique entre phase est disponible
- démarrez Workbench et sélectionnez la connexion.
- allez dans Gestion ou Instance et sélectionnez Fichier D'Options.
- Si Workbench vous demande la permission de lire le fichier de configuration, puis autorisez-le en appuyant deux fois sur OK.
- au Centre Place administrateur options fenêtre de fichier vient.
- Aller À Onglet InnoDB et vérifiez le innodb_large_prefix s'il n'est pas vérifié dans la section Général.
- 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, vous devez donc utiliser l'invite de commande
- démarrez CMD en tant qu'administrateur.
- allez dans director où le serveur mysql est installé la plupart des cas "C:\Program Files \ MySQL \ MySQL Server 5.7 \ bin" la commande so est "CD \" "fichiers de programme cd \ MySQL\MySQL Serveur 5.7 \ bin".
- exécutez maintenant la commande mysql - u nom d'utilisateur-p databasescheema Maintenant, il a demandé le mot de passe de l'utilisateur. Fournissez le mot de passe et entrez dans l'invite mysql.
- nous devons définir des paramètres globaux entrez les commandes ci-dessous une par une définir global innodb_large_prefix = on; définir innodb_file_format global = barracuda; définir innodb_file_per_table global = true;
- Maintenant, à la fin, nous devons modifier le ROW_FORMAT de la table requise par défaut son COMPACT, nous devons le définir sur DYNAMIQUE.
- utiliser la commande suivante modifier la table table_name ROW_FORMAT = dynamique;
- Fait
Modifiez votre classement. Vous pouvez utiliser utf8_general_ci qui prend en charge presque tous les
Basé sur la colonne donnée ci-dessous, ces 2 colonnes de chaîne variable utilisent utf8_general_ci
collation (utf8
charset est implicite).
Dans MySQL, utf8
charset utilise un maximum de 3 octets pour chaque personnage. Ainsi, il faudrait allouer 500 * 3 = 1500 octets, ce qui est beaucoup plus grand que les 767 octets que MySQL permet. 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 octet du jeu de caractères comme pas tous charset est une représentation d'un seul octet (comme vous l'avez présumé.) C'est-à-dire utf8
dans MySQL est utilise au plus 3 octets par caractère, 767/3≈255 caractères, et pour utf8mb4
, une représentation au plus 4 octets, 767/4≈191 caractères.
On sait aussi que MySQL
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
J'ai corrigé ce problème avec:
varchar(200)
Remplacé par
varchar(191)
Tous les varchar qui ont plus de 200 les remplacer par 191 ou les mettre du texte.
J'ai trouvé cette requête utile pour détecter quelles colonnes avaient un index violant 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')
Veuillez vérifier si sql_mode
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 mA.fichier cnf (mettre suivant)
innodb_large_prefix=on
Changer simplement utf8mb4
en utf8
lors de la création de tables 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;
.
Changez le jeu de caractères du champ d'index plaignant en "latin1"
c'est-à-dire modifier la TABLE TBL changer myfield MyField varchar (600) jeu de caractères latin1 par défaut NULL;
latin1 prend un octet pour un caractère au lieu de quatre
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;
Cela 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
Si vous avez changé innodb_log_file_size
récemment, essayez de restaurer la valeur précédente qui a fonctionné.
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: utilisation d'un terminal linux ou mac.
Sauvegarde (sans > redirection)
# mysqldump -u root -p databasename -r bkp.sql
Restaurer (sans la
# 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 " simple a disparu.
Pour laravel 5.6
Étapes à suivre
- allez dans app \ Providers \ AppServiceProvider.php
- ajoutez ceci au fournisseur / / (ne pas inclure le pipeline) utilisez Illuminate\Support \ Facades\Schema;
- dans la fonction de démarrage, ajoutez ce schéma / / (ne pas inclure pipeline):: defaultStringLength (191);
Que Tout, profiter.
Pour moi, le problème de "#1071 - clé spécifiée était trop long; la longueur maximale de la clé est de 767 octets " a été résolu après avoir changé la combinaison primarykey / uniquekey en limitant la taille de la colonne de 200.
ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);
Dans le cas où vous exécutez Laravel (laravel est maintenant par défaut sur 4 octets Unicode ce qui provoque cela), vous pouvez résoudre ce problème en changeant les lignes suivantes dans config/database.php à partir de
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
 à
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',