web-dev-qa-db-fra.com

# 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 eu ce message d'erreur:

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

Informations sur column1 et column2:

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 nécessite que 501 octets. Donc, le nombre total d'octets est 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
437
Steven

767 octets est la limite de préfixe énoncé pour les tables InnoDB dans MySQL version 5.6 (et les versions précédentes). Il faut 1000 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. Ceci est dû au fait que 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 possible consiste simplement à placer une limite inférieure sur vos champs VARCHAR.

Une autre option (selon la réponse de à cette question ) consiste à 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 si des améliorations vous permettraient d'implémenter les règles métier souhaitées sans respecter la limite de MySQL.

369
OMG Ponies

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 est la limitation.

368
PinkTurtle

Lorsque vous atteignez la limite. Définissez ce qui suit.

  • INNODB utf8VARCHAR(255)
  • INNODB utf8mb4VARCHAR(191)
259
Aley

MySQL suppose dans le pire des cas le nombre d'octets par caractère dans la chaîne. Pour l'encodage MySQL 'utf8', cela correspond à 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'actuel UTF-8.

En supposant que vous utilisiez 'utf8', votre première colonne contiendra 60 octets de l’index et votre seconde 1500 autres.

144
morganwahl

lancez cette requête avant votre requête:

SET @@global.innodb_large_prefix = 1;

cela augmentera la limite à 3072 bytes.

41
Raza Ahmed

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

37
Amber

Solution pour Laravel Framework

Selon Laravel 5.4. * Documentation ; Vous devez définir la longueur de chaîne par défaut dans la méthode boot 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, ce 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 puisse créer des index pour ces dernières. Vous pouvez le configurer en appelant la méthode Schema::defaultStringLength dans votre AppServiceProvider.

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

29
alishaukat

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. Ainsi, dans votre cas, 20 + 500 caractères = 20 * 3 + 500 * 3 = 1560 octets, soit plus que autorisé 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:

  1. Utilise un codage "moins cher" (celui qui nécessite moins d'octets par caractère)
    Dans mon cas, je devais ajouter un index unique sur une colonne contenant la chaîne d'article SEO, car je n'utilise que des caractères [A-z0-9\-] pour le référencement, j'ai utilisé latin1_general_ci, qui n'utilise qu'un octet par caractère. 
  2. 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 aurait la clé UNIQUE pour s’assurer que les valeurs de SEO sont uniques. J'ajouterais également l'index KEY à la colonne de référencement d'origine pour accélérer la recherche.
22
Buksy
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 violer 767 octets.

17
Anthony Rutledge

La réponse sur les raisons pour lesquelles vous obtenez un message d'erreur a déjà été répondue ici par de nombreux utilisateurs. Ma réponse concerne la façon de le réparer et de l'utiliser tel quel.

Référez-vous de ce lien .

  1. Ouvrez le client MySQL (ou client MariaDB). C'est 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 en utilisant 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 s)

  1. set global innodb_file_format=Barracuda;

Requête OK, 0 ligne affectée (0.02 sec)

  1. Allez dans votre base de données sur phpMyAdmin ou quelque chose comme ça pour une gestion facile. > Sélectionner la base de données> Afficher le tableau structure> Accéder à l'onglet Opérations. > Remplacez ROW_FORMAT par DYNAMIC et enregistrez les modifications.
  2. Accédez à l'onglet structure de la table> Cliquez sur le bouton Unique.
  3. Terminé. 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.

17
vee

vous pouvez ajouter une colonne du md5 de longues colonnes

15
diyism

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 façon de résoudre ce problème.

Lorsque vous utilisez utf8mb4, les caractères comptent pour 4 octets, alors que sous utf8, ils pourraient représenter 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 en utilisant utf8mb4, vous ne pouvez stocker que 191 caractères (767/4 = 191).

Vous pouvez absolument ajouter des index réguliers pour les champs VARCHAR(255) à 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:

 Sequel Pro screenshot showing index truncated at 191 characters

Cela convient, car les index classiques sont simplement 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 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, l'intégralité du contenu 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.

11
maknz

Voici ma réponse originale:

Je viens de déposer 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 dans tous les cas. 

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

Veuillez consulter 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

7
Châu Hồng Lĩnh

J'ai fait une recherche sur ce sujet a finalement eu un changement personnalisé

Pour MySQL workbench 6.3.7 Version, une phase graphique est disponible

  1. Démarrez Workbench et sélectionnez la connexion.
  2. Allez à la gestion ou à l'instance et sélectionnez Fichier d'options.
  3. Si Workbench vous demande la permission de lire le fichier de configuration, puis autorisez-le en appuyant deux fois sur OK.
  4. À la place centrale, la fenêtre du fichier d'options de l'administrateur s'affiche.
  5. Accédez à l'onglet InnoDB et vérifiez le préfixe innodb_large_ s'il n'a pas été 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, vous devez donc utiliser la commande Invite

  1. Démarrez CMD en tant qu'administrateur.
  2. Allez au directeur où le serveur mysql est installé. La plupart des cas, il se trouve à "C:\Program Files\MySQL\Serveur MySQL 5.7\bin" pour que la commande soit "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 . Entrez le mot de passe et entrez-le dans l'invite mysql.
  4. 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;
  5. Maintenant, à la dernière, nous devons 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é
6
Abhishek

change ton classement. Vous pouvez utiliser utf8_general_ci qui supporte presque tout

5
Nids Barthwal

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

varchar(200) 

remplacé par 

varchar(191)

tous les varchars qui ont plus de 200 les remplacent par 191 ou les mettent en texte. 

4
flik

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 après avoir essayé d'utiliser 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

3
Rick James

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;.

3
MajidJafari

Pour laravel 5.7 ou 5.6

Étapes à suivre

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

que tous, profitez-en.

2
Manojkiran.A

Selon la colonne indiquée ci-dessous, ces deux colonnes de chaîne de variable utilisent le classement utf8_general_ci (le jeu de caractères utf8 est impliqué). 

Dans MySQL, utf8 charset utilise un maximum de 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é). utf8 dans MySQL 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
2
Devy

Remplacez utf8mb4 par utf8 dans votre fichier d'importation.

enter image description here

2
Bryan

Dans mon cas, j'ai eu ce problème lorsque je sauvegardais une base de données à l'aide des caractères d'entrée/sortie 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 disparu.

1
Cassio Seffrin

J'ai trouvé cette requête utile pour détecter quelles colonnes avaient un index ne respectant 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')
1
Andrew

S'il vous plaît vérifier si sql_mode est comme

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

si c'est le cas, changez pour

sql_mode=NO_ENGINE_SUBSTITUTION

OR

redémarrez votre serveur en changeant votre fichier my.cnf (en mettant le suivant)

innodb_large_prefix=on
1
neel

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. Il faut 1000 octets pour les tables MyISAM. À partir de la version 5.7 de MySQL, cette limite a été augmentée à 3072 octets.

Exécuter ce qui suit sur le service vous donnant 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;
0
Rivers

Remplacez CHARSET du champ d'index se plaignant par "latin1"
c'est à dire. CHANGER myfield myfield varchar (600) JEU DE CARACTERES latin1 DEFAULT NULL;
latin1 prend un octet pour un caractère au lieu de quatre

0
Stan Holodnak

5 solutions de contournement

Ce problème existe avant que la limite ne soit augmentée dans 5.7.7 (MariaDB 10.2.2?).

Si vous atteignez la limite après avoir essayé d'utiliser CHARACTER SET utf8mb4. Ensuite, effectuez l’une des opérations suivantes (chacune présente un inconvénient) pour éviter l’erreur:

  • Passez à la version 5.7.7 (ou ultérieure) pour une limite de 3072 octets;
  • Modifiez 255 en 191 sur la VARCHAR - vous perdez les valeurs supérieures à 191 caractères (improbable?);
  • ALTER .. CONVERT TO utf8 - vous perdez Emoji et des Chinois;
  • Utilisez un index "préfixe" - vous perdez certains des avantages en termes de performances.
  • Ou ... Restez avec 5.6/5.5/10.1 mais effectuez 4 étapes pour augmenter la limite à 3072 octets:

    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)
    
0
Rick James

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

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
0
Nick Pridorozhko

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

0
10undertiber

Index Lengths & MySQL/MariaDB


Laravel utilise le caractère utf8mb4 défini par défaut, qui inclut le support pour le stockage de "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 ces dernières. 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);
}

Sinon, vous pouvez 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

0
Mayank Dudakiya