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
mysql
byte
varchar
mysql-error-1071
Steven
la source
la source
Réponses:
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:
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.
la source
utf8mb4
jeu 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)
. Leutf8
jeu 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)
Si quelqu'un rencontre des problèmes avec INNODB / Utf-8 pour essayer de mettre un
UNIQUE
index sur unVARCHAR(256)
champ, basculez-le surVARCHAR(255)
. Il semble que 255 soit la limitation.la source
3*255 = 765 < 767
.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 versVARCHAR(255)
, basculez versVARCHAR(191)
et basculez l'encodage versutf8mb4
(qui est en fait juste utf8, mais MySql voulait rester en arrière. Compat).Lorsque vous atteignez la limite. Réglez les éléments suivants.
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
la source
utf8mb4
limit (qui est l'encodage le plus utilisé pour les bases de données plus récentes, car il accepte les emojis / etc).ENGINE=InnoDB DEFAULT CHARSET=utf8
à la fin de laCREATE TABLE
déclaration que je pouvais avoir uneVARCHAR(255)
clé primaire. Merci.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.
la source
exécutez cette requête avant votre requête:
cela augmentera la limite à
3072 bytes
.la source
innodb_file_format
doit êtreBARRACUDA
et Au niveau de la table, vous devez utiliserROW_FORMAT=DYNAMIC
ouROW_FORMAT=COMPRESSED
. Voir le commentaire de @ cwd ci-dessus avec le guide.Solution pour Laravel Framework
Selon la documentation Laravel 5.4. * ; Vous devez définir la longueur de chaîne par défaut dans la
boot
méthode duapp/Providers/AppServiceProvider.php
fichier comme suit:Explication de ce correctif, fournie par la documentation Laravel 5.4. * :
la source
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.
la source
20 * 4 + 1
octets et la colonne de 500 caractères en500 * 4 + 2
octetsVARCHAR(256)
colonne avec unUNIQUE
index, 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?255*3 = 765; 256*3 = 768
. Il semble que votre serveur suppose 3 octets par caractère, @ArjanUTF8 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:
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.L'autre option pour moi était de créer une autre colonne qui stockerait le hachage du référencement, cette colonne aurait la
UNIQUE
clé pour garantir que les valeurs du référencement sont uniques. J'ajouterais également unKEY
index à la colonne SEO d'origine pour accélérer la recherche.la source
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 .
use my_database_name;
set global innodb_large_prefix=on;
set global innodb_file_format=Barracuda;
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.
la source
Vous avez reçu ce message car 1 octet équivaut à 1 caractère uniquement si vous utilisez le
latin-1
jeu de caractères. Si vous utilisezutf8
, chaque caractère sera considéré comme 3 octets lors de la définition de votre colonne clé. Si vous utilisezutf8mb4
, 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.la source
Remplacez
utf8mb4
parutf8
dans votre fichier d'importation.la source
vous pouvez ajouter une colonne du md5 de longues colonnes
la source
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 - commeunique_key
ici: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.
la source
Voici ma réponse originale:
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
(ouutf8mb4
), 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
la source
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:
- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes
la source
J'ai résolu ce problème avec:
remplacé par
tous les varchar qui en ont plus de 200 les remplacent par 191 ou leur mettent du texte.
la source
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
Pour les versions inférieures à 6.3.7, les options directes ne sont pas disponibles, il faut donc aller avec l'invite de commande
la source
set global innodb_default_row_format = DYNAMIC;
je vois ce message: ERREUR 1193 (HY000): variable système inconnue 'innodb_default_row_format'Pour laravel 5.7 à 6.0
Étapes à suivre
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
en haut.Schema::defaultStringLength(191);
que tout, profitez-en.
la source
email
uniques, 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.changez votre classement. Vous pouvez utiliser utf8_general_ci qui prend en charge presque tous
la source
Le simple fait de passer
utf8mb4
à lautf8
cré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;
.la source
Pour résoudre ce problème, cela fonctionne pour moi comme un charme.
la source
Sur la base de la colonne ci-dessous, ces 2 colonnes de chaînes variables utilisent le
utf8_general_ci
classement (leutf8
jeu de caractères est implicite).Dans MySQL,
utf8
charset 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
utf8
dans MySQL utilise au plus 3 octets par caractère, 767 / 3≈255 caractères et, pourutf8mb4
une représentation d'au plus 4 octets, 767 / 4≈191 caractères.Il est également connu que MySQL
la source
J'ai trouvé cette requête utile pour détecter les colonnes dont l'index violait la longueur maximale:
la source
Veuillez vérifier si
sql_mode
c'est commesi c'est le cas, passez à
OU
redémarrez votre serveur en changeant votre fichier my.cnf (en mettant ce qui suit)
la source
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)
Restaurer (sans la <redirection)
L'erreur "La clé spécifiée était trop longue; la longueur maximale de la clé est de 767 octets" a simplement disparu.
la source
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:
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
la source
Si vous créez quelque chose comme:
ça devrait être quelque chose comme
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
la source
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.
la source
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
la source
Si vous avez changé
innodb_log_file_size
récemment, essayez de restaurer la valeur précédente qui fonctionnait.la source