# 1071 - La clé spécifiée était trop longue. la longueur maximale de la clé est de 767 octets
-
06-07-2019 - |
Question
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 colonne 1 et la colonne 2:
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
Je pense que varchar(20)
ne nécessite que 21 octets tandis que varchar(500)
ne requiert que 501 octets. Donc, le nombre total d'octets est 522, moins de 767. Alors, pourquoi ai-je reçu le message d'erreur?
La solution
767 octets correspond à la limitation du préfixe déclaré pour Tables InnoDB dans MySQL version 5.6 (et versions antérieures). La longueur est de 1 000 octets pour les tables MyISAM. À partir de la version 5.7 de MySQL, 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 de 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, il s'agirait de trois octets, ce qui donnerait une longueur maximale de préfixe d'index de 254.
Une option consiste à 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, à savoir:
ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );
Faites des ajustements car vous avez besoin de la clé à appliquer, mais je me demande si cela vaudrait la peine d'examiner 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 souhaitées sans toucher à MySQL. limitation.
Autres conseils
Si quelqu'un a des problèmes avec INNODB / Utf-8 pour essayer de placer un index UNIQUE
sur un champ VARCHAR(256)
, réglez-le sur VARCHAR(255)
. Il semble que 255 soit la limite.
Lorsque vous atteignez la limite. Définissez les éléments suivants.
- INNODB
utf8
VARCHAR(255)
- INNODB
utf8mb4
VARCHAR(191)
MySQL suppose dans le pire des cas le nombre d'octets par caractère dans la chaîne. Pour l'encodage MySQL 'utf8', il s'agit de 3 octets par caractère, car cet encodage n'autorise pas les caractères supérieurs à U+FFFF
. Pour l'encodage MySQL 'utf8mb4', il s'agit de 4 octets par caractère, puisque c'est ce que MySQL appelle l'UTF-8.
En supposant que vous utilisiez 'utf8', votre première colonne contiendra 60 octets de l'index, et votre seconde 1500 autres.
exécuter 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 plusieurs octets par caractère.
Solution pour le framework Laravel
Conformément à la documentation Laravel 5.4. * ; Vous devez définir la longueur de chaîne par défaut dans la boot
méthode du fichier app/Providers/AppServiceProvider.php
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 inclut la prise en charge du stockage de & "emojis &"; dans la base de données. Si vous utilisez 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 en créer un index. Vous pouvez le configurer en appelant la méthodeSchema::defaultStringLength
dans votreAppServiceProvider
.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 comment activer correctement cette option.
Je pense que varchar (20) ne nécessite que 21 octets tandis que varchar (500) seulement nécessite 501 octets. Donc, le nombre total d'octets est 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. Dans votre cas, par conséquent, 20 + 500 caractères = 20 * 3 + 500 * 3 = 1560 octets, soit < strong> 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:
- Utilisez & "moins cher &"; codage (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 la chaîne d’article SEO, car j’utilise uniquement[A-z0-9\-]
des caractères pour le référencement, j’ai utilisélatin1_general_ci
qui n’utilise qu’un octet par caractère. La colonne peut donc avoir une longueur de 767 octets. - Créez un hachage à partir de votre colonne et utilisez un index unique uniquement sur cette
L'autre option pour moi était de créer une autre colonne qui stockerait le hachage de SEO, cette colonne auraitUNIQUE
clé pour garantir que les valeurs de SEO sont uniques. J'ajouterais égalementKEY
l'index à la colonne SEO d'origine pour accélérer la recherche.
De nombreux utilisateurs ont déjà répondu à la question de savoir pourquoi vous obtenez un message d'erreur. Ma réponse concerne la façon de le réparer et de l'utiliser tel quel.
Voir ce lien .
- Ouvrez le client MySQL (ou le client MariaDB). C'est un outil en 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;
La base de données a été modifiée
-
set global innodb_large_prefix=on;
Requête OK, 0 ligne affectée (0,00 s)
-
set global innodb_file_format=Barracuda;
Requête OK, 0 ligne affectée (0.02 sec)
- Allez dans votre base de données sur phpMyAdmin ou quelque chose comme ça pour une gestion facile. > Sélectionnez la base de données & Gt; Afficher la table structure & Gt; Accédez à l'onglet Opérations . > Remplacez ROW_FORMAT par DYNAMIC et enregistrez les modifications.
- Accédez à l'onglet Structure de la table > Cliquez sur le bouton Unique .
- Fait. Maintenant, il ne devrait pas y avoir d'erreur.
Le problème de ce correctif est que vous exportez la base de données vers un autre serveur (par exemple de localhost vers un 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.
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 de clé. Si vous utilisez utf8mb4
, chaque caractère sera considéré comme 4 octets lors de la définition de votre colonne de clé. Ainsi, vous devez multiplier la limite de caractères du champ de votre clé par, 1, 3 ou 4 (dans mon exemple) pour déterminer le nombre d'octets que le champ de clé tente d'autoriser. Si vous utilisez uft8mb4, vous ne pouvez définir que 191 caractères pour un champ natif, InnoDB, clé primaire. Il suffit de ne pas dépasser 767 octets.
vous pouvez ajouter une colonne du md5 des colonnes longues
Nous avons rencontré ce problème lorsque nous avons essayé d'ajouter un index UNIQUE à un champ VARCHAR (255) à l'aide de utf8mb4. Bien que le problème soit déjà bien décrit, je souhaitais ajouter quelques conseils pratiques sur la manière de résoudre ce problème.
Lors de l’utilisation de utf8mb4, les caractères comptent pour 4 octets, alors que sous utf8, ils pourraient correspondre à 3 octets. Les bases de données InnoDB ont pour 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 avec utf8mb4, vous ne pouvez enregistrer que 191 caractères (767/4 = 191).
Vous pouvez absolument ajouter des index réguliers pour VARCHAR(255)
les champs à l'aide de utf8mb4, mais il se trouve que la taille de l'index est automatiquement tronquée à 191 caractères - comme unique_key
ici:
Cela convient, car les index classiques sont simplement utilisés pour aider MySQL à parcourir 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 les index normaux, mais génère une erreur explicite lorsque vous essayez 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 en fait indexer la valeur entière et pas seulement une partie de celle-ci.
À la fin de la journée, si vous souhaitez avoir un index unique sur un champ, le contenu complet du champ doit tenir dans l’index. Pour utf8mb4, cela signifie que vous réduisez la longueur de votre champ VARCHAR à 191 caractères ou moins. Si vous n'avez pas besoin de utf8mb4 pour cette table ou ce champ, vous pouvez le remettre à utf8 et pouvoir conserver vos champs de 255 longueurs.
Voici ma réponse initiale:
Je viens de déposer la base de données et de le recréer 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 dans 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 comportant plus d'une certaine longueur de caractères. Dans le cas de <=>, cette certaine longueur est 191.
Reportez-vous à 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
J'ai effectué des recherches sur ce sujet et obtenu un changement personnalisé
Pour MySQL Workbench 6.3.7 Version, une phase graphique est disponible
- Démarrez Workbench et sélectionnez la connexion.
- Accédez à la gestion ou à l'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, la fenêtre du fichier d'options de l'administrateur s'affiche.
- Allez sur l'onglet InnoDB et vérifiez le préfixe innodb_large_ s'il n'a pas été coché 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 vous connecter avec une invite de commande
.- Démarrer CMD en tant qu'administrateur.
- Aller au directeur où le serveur mysql est installé La plupart des cas, c'est à " C: \ Program Files \ MySQL \ Serveur MySQL 5.7 \ bin " alors le commandement est " cd \ " " cd Program Files \ MySQL \ Serveur MySQL 5.7 \ bin ".
- Commande maintenant lancée mysql -u nom d'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.
- Nous devons définir certains paramètres globaux et entrer les commandes ci-dessous une à une. set global innodb_large_prefix = on; set global innodb_file_format = barracuda; set global innodb_file_per_table = true;
- À la dernière modification, nous devons modifier le ROW_FORMAT de la table requise. Par défaut, son COMPACT doit être défini sur DYNAMIC.
- utilise la commande suivante alter table nom_table ROW_FORMAT = DYNAMIC;
- terminé
J'ai résolu ce problème avec:
varchar(200)
remplacé par
varchar(191)
tous les varchars qui ont plus de 200 remplacent par 191 ou les mettent en texte.
5 solutions de contournement:
La limite a été augmentée à 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 en raison d'une tentative d'utilisation de CHARACTER SET utf8mb4. Ensuite, effectuez 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
changez votre classement. Vous pouvez utiliser utf8_general_ci , qui prend en charge la quasi-totalité des
. Changer simplement de utf8mb4
à 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;
.
Pour laravel 5,7 ou 5,6 ou 5,8
Étapes à suivre
- Accédez à
App\Providers\AppServiceProvider.php
. - Ajoutez ceci au fournisseur
use Illuminate\Support\Facades\Schema;
en haut. - Dans la fonction de démarrage Ajouter ceci
Schema::defaultStringLength(191);
que tous, profitez-en.
Sur la base de la colonne indiquée ci-dessous, ces 2 colonnes de chaîne de variable utilisent utf8_general_ci
un classement (utf8
jeu de caractères est impliqué).
Dans MySQL, utf8mb4
jeu de caractères utilise au maximum 3 octets pour chaque caractère. Ainsi, 500 * 3 = 1500 octets devraient être alloués, ce qui est bien supérieur aux 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 d'octet du jeu de caractères, car chaque jeu de caractères n'est pas une représentation à un seul octet (comme vous l'aviez supposé). I.E. <=> MySQL utilise au maximum 3 octets par caractère, 767/3 & # 8776; 255 caractères, et pour <=> une représentation maximale de 4 octets, 767/4 & # 8776; 191 caractères.
On sait aussi que MySQL
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
J'ai trouvé cette requête utile pour détecter les colonnes dont l'index ne respectait pas 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, remplacez par
sql_mode=NO_ENGINE_SUBSTITUTION
OU
redémarrez votre serveur en changeant votre fichier my.cnf (en mettant les suivants)
innodb_large_prefix=on
Dans mon cas, j’ai eu ce problème lors de la sauvegarde d’une base de données à l’aide des caractères de sortie / entrée de redirection Linux. Par conséquent, je change la syntaxe comme décrit ci-dessous. PS: 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 " simple disparu.
Longueur d'index & amp; MySQL / MariaDB
Laravel utilise le caractère utf8mb4 défini par défaut, qui inclut la prise en charge du stockage de & "emojis &"; dans la base de données. Si vous utilisez 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 en créer un index. Vous pouvez le configurer 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 de la documentation officielle de laravel: https://laravel.com/ docs / 5.7 / migrations
Modifiez CHARSET du champ d'index se plaignant en " latin1 "
ALTER TABLE tbl MODIFIER myfield myfield varchar (600) JEU DE CARACTERES latin1 DEFAULT 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 le caractère unique de cette colonne par rapport au code ou ajouter une nouvelle colonne en tant que MD5 ou SHA1 de la colonne varchar
En raison des limitations de préfixes, cette erreur se produira. 767 octets est la limite de préfixe indiquée pour les tables InnoDB dans les versions de MySQL antérieures à 5.7. La longueur est de 1 000 octets pour les tables MyISAM. À partir de la version 5.7 de MySQL, cette limite a été augmentée à 3072 octets.
L'exécution de ce qui suit sur le service vous générant l'erreur devrait résoudre votre problème. Ceci doit être exécuté dans la CLI de MYSQL.
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;
Pour résoudre ce problème, cela fonctionne pour moi comme un charme.
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
Si vous avez changé innodb_log_file_size
récemment, essayez de restaurer la valeur précédente qui fonctionnait.
Pour moi, le problème de " # 1071 - La clé spécifiée était trop long; La longueur maximale de la clé est de 767 octets " résolus après modification de la combinaison primarykey / uniquekey en limitant la taille de la colonne à 200.
ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);