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.
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
.
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
.
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));
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 .
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
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.
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.
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.
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).
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.
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 problemtextfield
TEXT
devront être uniques et toute différence subséquente sera ignorée.
Allez dans mysql edit table
-> changez le type de colonne en varchar(45)
.
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));
Vous devez définir le type de colonne sur varchar
ou integer
pour l'indexation.
Utiliser comme ça
@Id
@Column(name = "userEmailId", length=100)
private String userEmailId;