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
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.
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.
Lorsque vous atteignez la limite. Définissez ce qui suit.
utf8
VARCHAR(255)
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', 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.
lancez 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 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éthodeSchema::defaultStringLength
dans votreAppServiceProvider
.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.
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.
[A-z0-9\-]
pour le référencement, j'ai utilisé latin1_general_ci
, qui n'utilise qu'un octet par caractère. 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.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.
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 .
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 s)
set global innodb_file_format=Barracuda;
Requête OK, 0 ligne affectée (0.02 sec)
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.
vous pouvez ajouter une colonne du md5 de longues colonnes
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:
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.
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
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
Pour les versions inférieures à 6.3.7, les options directes ne sont pas disponibles, vous devez donc utiliser la commande Invite
change ton classement. Vous pouvez utiliser utf8_general_ci qui supporte presque tout
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.
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
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;
.
Pour laravel 5.7 ou 5.6
Étapes à suivre
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
en haut.Schema::defaultStringLength(191);
que tous, profitez-en.
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
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.
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')
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
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;
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
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:
VARCHAR
- vous perdez les valeurs supérieures à 191 caractères (improbable?);ALTER .. CONVERT TO utf8
- vous perdez Emoji et des Chinois;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)
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 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
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