web-dev-qa-db-fra.com

Erreur MySQL: spécification de clé sans longueur de clé

J'ai une table avec une clé primaire qui est un varchar (255). Dans certains cas, 255 caractères ne suffisent pas. J'ai essayé de changer le champ en un texte, mais j'obtiens l'erreur suivante:

BLOB/TEXT column 'message_id' used in key specification without a key length

comment puis-je réparer cela?

edit: Je devrais également souligner que cette table a une clé primaire composée avec plusieurs colonnes.

298
GSto

L'erreur se produit car MySQL ne peut indexer que les N premiers caractères d'une colonne BLOB ou TEXT. Ainsi, l’erreur survient principalement lorsqu’il existe un type de champ/colonne de TEXT ou BLOB ou ceux qui appartiennent à TEXT ou BLOB tels que TINYBLOB, MEDIUMBLOB, LONGBLOB, TINYTEXT, MEDIUMTEXT et LONGTEXT que vous essayez de créer une clé primaire ou un index. Avec BLOB ou TEXT complet sans la valeur de longueur, MySQL ne peut pas garantir l’unicité de la colonne car elle est de taille variable et dynamique. Ainsi, lorsque vous utilisez les types BLOB ou TEXT comme index, la valeur de N doit être fournie afin que MySQL puisse déterminer la longueur de la clé. Cependant, MySQL ne prend pas en charge la limite de longueur de clé pour TEXT ou BLOB. TEXT(88) ne fonctionnera tout simplement pas.

L'erreur apparaît également lorsque vous essayez de convertir une colonne de table de type non-TEXT et non-BLOB telle que VARCHAR et ENUM en type TEXT ou BLOB, la colonne étant déjà définie en tant que contrainte ou index unique. La commande Alter Table SQL échouera.

La solution au problème consiste à supprimer la colonne TEXT ou BLOB de l'index ou de la contrainte unique ou de définir un autre champ comme clé primaire. Si vous ne pouvez pas faire cela et que vous souhaitez limiter la colonne TEXT ou BLOB, essayez d'utiliser le type VARCHAR et placez-y une limite de longueur. Par défaut, VARCHAR est limité à un maximum de 255 caractères et sa limite doit être spécifiée implicitement entre crochets juste après sa déclaration, c'est-à-dire que VARCHAR(200) le limitera à 200 caractères uniquement.

Parfois, même si vous n'utilisez pas le type associé à TEXT ou BLOB dans votre table, l'erreur 1170 peut également apparaître. Cela se produit dans des situations telles que, par exemple, lorsque vous spécifiez la colonne VARCHAR comme clé primaire, mais que vous définissez de manière incorrecte sa longueur ou la taille de ses caractères. VARCHAR ne peut accepter que 256 caractères. Par conséquent, tout ce qui est comme VARCHAR(512) obligera MySQL à convertir automatiquement VARCHAR(512) en un type de données SMALLTEXT, qui échouera par la suite avec l’erreur 1170 sur la longueur de la clé si la colonne est utilisée comme clé primaire ou unique ou non. index unique. Pour résoudre ce problème, spécifiez une valeur inférieure à 256 comme taille du champ VARCHAR.

Référence: Erreur MySQL 1170 (42000): Colonne BLOB/TEXT utilisée dans la spécification de clé sans longueur de clé

490
OMG Ponies

Vous devez définir la partie principale d'une colonne TEXT que vous souhaitez indexer.

InnoDB a une limite de 768 octets par clé d'index et vous ne pourrez pas créer d'index plus long que cela.

Cela fonctionnera bien:

CREATE TABLE t_length (
      mydata TEXT NOT NULL,
      KEY ix_length_mydata (mydata(255)))
    ENGINE=InnoDB;

Notez que la valeur maximale de la taille de la clé dépend du jeu de caractères de la colonne. Il s'agit de 767 caractères pour un jeu de caractères à un octet tel que LATIN1 et uniquement de 255 caractères pour UTF8 (MySQL utilise uniquement BMP qui requiert au plus 3 octets par caractère)

Si vous souhaitez que votre colonne entière soit le PRIMARY KEY, calculez le hash SHA1 ou MD5 et utilisez-le comme PRIMARY KEY.

73
Quassnoi

Vous pouvez spécifier la longueur de la clé dans la demande de modification de table, par exemple:

alter table authors ADD UNIQUE(name_first(20), name_second(20));
54
Mike Evans

MySQL n'autorise pas l'indexation d'une valeur complète de colonnes BLOB, TEXT et long VARCHAR car les données qu'elles contiennent peuvent être énormes et implicitement, l'index de base de données sera grand, ce qui signifie qu'aucun avantage de l'index.

MySQL exige que vous définissiez les N premiers caractères à indexer. L'astuce consiste à choisir un nombre N suffisamment long pour offrir une bonne sélectivité, mais suffisamment court pour économiser de l'espace. Le préfixe doit être suffisamment long pour rendre l’index presque aussi utile que si vous aviez indexé la totalité de la colonne.

Avant d’aller plus loin, définissons quelques termes importants. La sélectivité index est le rapport de le total des valeurs indexées distinctes et le nombre total de lignes. Voici un exemple de table de test:

+-----+-----------+
| id  | value     |
+-----+-----------+
| 1   | abc       |
| 2   | abd       |
| 3   | adg       |
+-----+-----------+

Si nous n'indexons que le premier caractère (N = 1), alors la table d'index ressemblera à la table suivante:

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| a             | 1,2,3     |
+---------------+-----------+

Dans ce cas, la sélectivité de l’indice est égale à IS = 1/3 = 0,33.

Voyons maintenant ce qui se passera si nous augmentons le nombre de caractères indexés à deux (N = 2).

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| ab             | 1,2      |
| ad             | 3        |
+---------------+-----------+

Dans ce scénario, IS = 2/3 = 0.66, ce qui signifie que nous avons augmenté la sélectivité de l’indice, mais nous avons également augmenté la taille de l’indice. L'astuce consiste à trouver le nombre minimal N qui résultera au maximum {sélectivité d'index)

Il existe deux approches pour effectuer des calculs pour votre table de base de données. Je vais faire une démonstration sur le cette base de données .

Supposons que nous voulions ajouter la colonne nom_nom dans la table employés à l'index et définir le plus petit nombre N qui produira le meilleur index. sélectivité.

Premièrement, identifions les noms de famille les plus fréquents:

select count(*) as cnt, last_name 
from employees 
group by employees.last_name 
order by cnt

+-----+-------------+
| cnt | last_name   |
+-----+-------------+
| 226 | Baba        |
| 223 | Coorg       |
| 223 | Gelosh      |
| 222 | Farris      |
| 222 | Sudbeck     |
| 221 | Adachi      |
| 220 | Osgood      |
| 218 | Neiman      |
| 218 | Mandell     |
| 218 | Masada      |
| 217 | Boudaillier |
| 217 | Wendorf     |
| 216 | Pettis      |
| 216 | Solares     |
| 216 | Mahnke      |
+-----+-------------+
15 rows in set (0.64 sec)

Comme vous pouvez le constater, le nom de famille Baba est le plus fréquent. Nous allons maintenant trouver les préfixes nom_nom les plus fréquents, commençant par les préfixes de cinq lettres.

+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa  |
| 758 | Mande  |
| 711 | Schwa  |
| 562 | Angel  |
| 561 | Gecse  |
| 555 | Delgr  |
| 550 | Berna  |
| 547 | Peter  |
| 543 | Cappe  |
| 539 | Stran  |
| 534 | Canna  |
| 485 | Georg  |
| 417 | Neima  |
| 398 | Petti  |
| 398 | Duclo  |
+-----+--------+
15 rows in set (0.55 sec)

Chaque préfixe contient beaucoup plus d’occurrences, ce qui signifie que nous devons augmenter le nombre N jusqu’à ce que les valeurs soient presque identiques à celles de l’exemple précédent.

Voici les résultats de la recherche pour N = 9

select count(*) as cnt, left(last_name,9) as prefix 
from employees 
group by prefix 
order by cnt desc 
limit 0,15;

+-----+-----------+
| cnt | prefix    |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba      |
| 223 | Coorg     |
| 223 | Gelosh    |
| 222 | Sudbeck   |
| 222 | Farris    |
| 221 | Adachi    |
| 220 | Osgood    |
| 218 | Mandell   |
| 218 | Neiman    |
| 218 | Masada    |
| 217 | Wendorf   |
| 217 | Boudailli |
| 216 | Cummings  |
| 216 | Pettis    |
+-----+-----------+

Voici les résultats pour N = 10.

+-----+------------+
| cnt | prefix     |
+-----+------------+
| 226 | Baba       |
| 223 | Coorg      |
| 223 | Gelosh     |
| 222 | Sudbeck    |
| 222 | Farris     |
| 221 | Adachi     |
| 220 | Osgood     |
| 218 | Mandell    |
| 218 | Neiman     |
| 218 | Masada     |
| 217 | Wendorf    |
| 217 | Boudaillie |
| 216 | Cummings   |
| 216 | Pettis     |
| 216 | Solares    |
+-----+------------+
15 rows in set (0.56 sec)

Ce sont de très bons résultats. Cela signifie que nous pouvons créer un index sur la colonne last_name en indexant uniquement les 10 premiers caractères. Dans la définition de table, la colonne last_name est définie comme étant VARCHAR(16), ce qui signifie que nous avons enregistré 6 octets (ou plus s'il existe des caractères UTF8 dans le nom de famille) par entrée. Dans ce tableau, il y a 1637 valeurs distinctes multipliées par 6 octets, soit environ 9 Ko, et imaginez comment ce nombre augmenterait si notre table contenait des millions de lignes.

Vous pouvez lire d’autres méthodes de calcul du nombre de N dans mon message Les index préfixés dans MySQL .

16
MrD
alter table authors ADD UNIQUE(name_first(767), name_second(767));

NOTE: 767 est le nombre maximal de caractères jusqu'à lequel MySQL indexera les colonnes lors du traitement des index blob/text

Réf: http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html

4
Abhishek Goel

Ne pas avoir de longues valeurs en tant que clé primaire. Cela va détruire votre performance. Reportez-vous au manuel mysql, section 13.6.13 intitulée «Réglage des performances d’InnoDB et résolution des problèmes».

Au lieu de cela, utilisez une clé de substitution int en tant que primaire (avec auto_increment) et votre clé loong en tant que UNIQUE secondaire.

3
Per Lindberg

Une autre excellente solution consiste à créer votre champ TEXT sans contrainte unique et à ajouter un champ VARCHAR frère unique, contenant un condensé (MD5, SHA1, etc.) du champ TEXT. Calculez et stockez le résumé sur l'intégralité du champ TEXT lorsque vous insérez ou mettez à jour le champ TEXT, vous aurez alors une contrainte d'unicité sur l'intégralité du champ TEXT (plutôt qu'une partie en tête) sur laquelle vous pourrez effectuer une recherche rapide.

2
par

Ajoutez une autre colonne varChar (255) (avec par défaut une chaîne vide non null) pour contenir le dépassement de capacité lorsque 255 caractères ne suffisent pas et modifiez cette clé de clé pour utiliser les deux colonnes. Cela ne ressemble toutefois pas à un schéma de base de données bien conçu, et je recommanderais à un modélisateur de données d'examiner ce que vous avez en vue de le refactoriser pour davantage de normalisation.

1
Charles Bretana

Personne n’en a parlé jusqu’à présent ... avec utf8mb4, qui est de 4 octets et peut également stocker des émoticônes (nous ne devrions jamais utiliser plus de 3 octets utf8) et nous pouvons éviter des erreurs telles que Incorrect string value: \xF0\x9F\x98\... nous ne devrions pas utiliser de type VARCHAR (255) mais plutôt VARCHAR (191) parce que dans le cas où utf8mb4 et VARCHAR (255) sont conservés, les mêmes données sont stockées hors page et vous ne pouvez pas créer d’index pour la colonne VARCHAR (255), mais pour VARCHAR (191). En effet, la taille de colonne indexée maximale est de 767 octets pour ROW_FORMAT = COMPACT ou ROW_FORMAT = REDUNDANT.

Pour les formats de ligne les plus récents, ROW_FORMAT = DYNAMIC ou ROW_FORMAT = COMPRESSED (ce qui nécessite un format de fichier plus récent innodb_file_format = Barracuda pas l'ancienne Antelope). La taille de colonne indexée maximale est 3072. Elle est disponible depuis MySQL> = 5.6.3 lorsque innodb_large_prefix = 1 (désactivé par défaut) MySQL <= 5.7.6 et activé par défaut pour MySQL> = 5.7.7). Donc, dans ce cas, nous pouvons utiliser VARCHAR (768) pour utf8mb4 (ou VARCHAR (1024) pour ancien utf8) pour la colonne indexée. L'option innodb_large_prefix est obsolète depuis la version 5.7.7 car son comportement est intégré à MySQL 8 (dans cette version, l'option est supprimée).

0
mikep

De plus, si vous souhaitez utiliser l'index dans ce champ, vous devez utiliser le moteur de stockage MyISAM et le type d'index FULLTEXT.

0

La solution au problème est que, dans votre instruction CREATE TABLE, vous pouvez ajouter la contrainte UNIQUE ( problemtextfield(300) ) après la création de définitions de colonne pour spécifier une longueur key de 300 caractères pour un champ TEXT, par exemple. Ensuite, les premiers 300 caractères du champ problemtextfieldTEXT devront être uniques et toute différence subséquente sera ignorée.

0
Who Dunnit

Allez dans mysql edit table-> changez le type de colonne en varchar(45).

0
Manoj Mishra

J'ai eu cette erreur lors de l'ajout d'un index à une table avec des colonnes de type texte. Vous devez déclarer le montant que vous souhaitez utiliser pour chaque type de texte.

Placez le montant dans la parenthèse ()

Si vous utilisez trop d'octets, vous pouvez déclarer une taille entre crochets pour varchar afin de réduire la quantité utilisée pour l'indexation. Cela est vrai même si vous avez déjà déclaré une taille pour un type tel que varchar (1000). Vous n'avez pas besoin de créer une nouvelle table comme d'autres l'ont dit.

Ajout d'index

alter table test add index index_name(col1(255),col2(255));

Ajout d'index unique

alter table test add unique index_name(col1(255),col2(255));
0
stealth

Vous devez définir le type de colonne sur varchar ou integer pour l'indexation.

0
Manoj Mishra

Utiliser comme ça

@Id
@Column(name = "userEmailId", length=100)
private String userEmailId;
0
Krishna Das