Ich habe eine Tabelle mit einem Primärschlüssel, der ein Varchar ist (255). In einigen Fällen sind 255 Zeichen nicht ausreichend. Ich habe versucht, das Feld in einen Text zu ändern, erhalte jedoch die folgende Fehlermeldung:
BLOB/TEXT column 'message_id' used in key specification without a key length
Wie kann ich das beheben?
Bearbeiten: Ich sollte auch darauf hinweisen, dass diese Tabelle einen zusammengesetzten Primärschlüssel mit mehreren Spalten hat.
mysql
sql
mysql-error-1170
GSto
quelle
quelle
UNIQUE
Schlüssel hat?Antworten:
Der Fehler tritt auf, weil MySQL nur die ersten N Zeichen eines BLOBs oder einer
TEXT
Spalte indizieren kann . So Der Fehler tritt vor allem , wenn es ein Feld / Spalte Typ istTEXT
oder BLOB oder solche , gehören inTEXT
oderBLOB
Typen wieTINYBLOB
,MEDIUMBLOB
,LONGBLOB
,TINYTEXT
,MEDIUMTEXT
, undLONGTEXT
dass Sie versuchen , einen Primärschlüssel oder Index zu machen. Mit vollemBLOB
oderTEXT
ohne Längenwert kann MySQL die Eindeutigkeit der Spalte nicht garantieren, da sie eine variable und dynamische Größe hat. Wenn Sie alsoBLOB
oderTEXT
als Index verwenden, muss der Wert von N angegeben werden, damit MySQL die Schlüssellänge bestimmen kann. MySQL unterstützt jedoch keine Schlüssellängenbeschränkung fürTEXT
oderBLOB
.TEXT(88)
wird einfach nicht funktionieren.Der Fehler wird auch angezeigt, wenn Sie versuchen, eine Tabellenspalte von
non-TEXT
und nachnon-BLOB
wieVARCHAR
undENUM
inTEXT
oderBLOB
Typ zu konvertieren , wobei die Spalte bereits als eindeutige Einschränkungen oder Index definiert wurde. Der Befehl "Tabelle SQL ändern" schlägt fehl.Die Lösung des Problems besteht darin, die Spalte
TEXT
oderBLOB
aus dem Index oder der eindeutigen Einschränkung zu entfernen oder ein anderes Feld als Primärschlüssel festzulegen. Wenn Sie dies nicht tun können und die SpalteTEXT
oder einschränken möchtenBLOB
, versuchen Sie,VARCHAR
type zu verwenden und die Länge zu begrenzen. StandardmäßigVARCHAR
ist es auf maximal 255 Zeichen begrenzt, und sein Limit muss implizit in einer Klammer direkt nach seiner Deklaration angegeben werden, dhVARCHAR(200)
es wird auf nur 200 Zeichen begrenzt.Manchmal wird auch der Fehler 1170 angezeigt , obwohl Sie keinen
TEXT
oder einenBLOB
verwandten Typ in Ihrer Tabelle verwenden. Dies geschieht beispielsweise, wenn Sie eineVARCHAR
Spalte als Primärschlüssel angeben , deren Länge oder Zeichengröße jedoch falsch festlegen.VARCHAR
kann nur bis zu 256 Zeichen akzeptieren, sodassVARCHAR(512)
MySQL gezwungen wird, das automatischVARCHAR(512)
in einenSMALLTEXT
Datentyp zu konvertieren , der anschließend mit Fehler 1170 bei der Schlüssellänge fehlschlägt, wenn die Spalte als Primärschlüssel oder eindeutiger oder nicht eindeutiger Index verwendet wird. Geben Sie zur Lösung dieses Problems eine Zahl unter 256 alsVARCHAR
Feldgröße an.Referenz: MySQL-Fehler 1170 (42000): BLOB / TEXT-Spalte, die in der Schlüsselspezifikation ohne Schlüssellänge verwendet wird
quelle
Sie sollten definieren, welchen führenden Teil einer
TEXT
Spalte Sie indizieren möchten.InnoDB
Die Anzahl der768
Bytes pro Indexschlüssel ist begrenzt, und Sie können keinen längeren Index erstellen.Dies wird gut funktionieren:
Beachten Sie, dass der Maximalwert der Schlüsselgröße vom Spaltenzeichensatz abhängt. Es sind
767
Zeichen für einen Einzelbyte-Zeichensatz wieLATIN1
und nur255
Zeichen fürUTF8
(MySQL
nur Verwendungen, fürBMP
die höchstens3
Bytes pro Zeichen erforderlich sind )Wenn Sie möchten, dass Ihre gesamte Spalte die ist
PRIMARY KEY
, berechnen SieSHA1
oderMD5
hashen Sie und verwenden Sie sie alsPRIMARY KEY
.quelle
REDUNDANT
oderCOMPACT
verwenden. Beispielsweise können Sie diese Grenze mit einem Spaltenpräfixindex von mehr als 255 Zeichen für eineTEXT
oder eineVARCHAR
Spalte erreichen, vorausgesetzt, ein Zeichensatz utf8mb3 und maximal 3 Byte für jedes Zeichen.REDUNDANT
undCOMPACT
waren die einzigen verfügbaren Formate zum Zeitpunkt der Beantwortung dieser Antwort.Sie können die Schlüssellänge in der Anforderung zum Ändern der Tabelle angeben, z. B.:
quelle
MySQL Verbietet einen vollen Wert indizieren
BLOB
,TEXT
und langeVARCHAR
Spalten , weil Daten , die sie enthalten , können sehr groß sein, und implizit DB - Index wird groß sein, keinen Nutzen aus dem Index bedeutet.MySQL erfordert, dass Sie die ersten N zu indizierenden Zeichen definieren. Der Trick besteht darin, eine Zahl N zu wählen, die lang genug ist, um eine gute Selektivität zu erzielen, aber kurz genug, um Platz zu sparen. Das Präfix sollte lang genug sein, um den Index fast so nützlich zu machen, wie es wäre, wenn Sie die gesamte Spalte indiziert hätten.
Bevor wir weiter gehen, definieren wir einige wichtige Begriffe. Die Indexselektivität ist das Verhältnis der insgesamt unterschiedlichen indizierten Werte und der Gesamtzahl der Zeilen . Hier ist ein Beispiel für eine Testtabelle:
Wenn wir nur das erste Zeichen indizieren (N = 1), sieht die Indextabelle wie folgt aus:
In diesem Fall ist die Indexselektivität gleich IS = 1/3 = 0,33.
Lassen Sie uns nun sehen, was passieren wird, wenn wir die Anzahl der indizierten Zeichen auf zwei erhöhen (N = 2).
In diesem Szenario ist IS = 2/3 = 0,66, was bedeutet, dass wir die Indexselektivität erhöht haben, aber wir haben auch die Größe des Index erhöht. Der Trick besteht darin, die minimale Zahl N zu finden, die zu maximaler Indexselektivität führt .
Es gibt zwei Ansätze, mit denen Sie Berechnungen für Ihre Datenbanktabelle durchführen können. Ich werde auf diesem Datenbank-Dump demonstrieren .
Lassen Sie uns sagen , dass wir Spalte hinzufügen möchten last_name in der Tabelle Mitarbeiter auf den Index, und wir wollen die kleinste Zahl definieren , N , die die beste Index Selektivität produzieren.
Lassen Sie uns zuerst die häufigsten Nachnamen identifizieren:
Wie Sie sehen können, ist der Nachname Baba der häufigste. Jetzt werden wir die am häufigsten vorkommenden Nachnamen- Präfixe finden, beginnend mit Präfixen aus fünf Buchstaben.
Es gibt viel mehr Vorkommen von jedem Präfix, was bedeutet, dass wir die Zahl N erhöhen müssen, bis die Werte fast dieselben wie im vorherigen Beispiel sind.
Hier sind die Ergebnisse für N = 9
Hier sind Ergebnisse für N = 10.
Das sind sehr gute Ergebnisse. Dies bedeutet, dass wir einen Index für eine Spalte
last_name
erstellen können, wobei nur die ersten 10 Zeichen indiziert werden. In der Tabellendefinitionlast_name
ist die Spalte definiert alsVARCHAR(16)
, und dies bedeutet, dass wir 6 Bytes (oder mehr, wenn der Nachname UTF8-Zeichen enthält) pro Eintrag gespeichert haben. In dieser Tabelle gibt es 1637 verschiedene Werte multipliziert mit 6 Bytes, was ungefähr 9 KB entspricht. Stellen Sie sich vor, wie diese Zahl wachsen würde, wenn unsere Tabelle Millionen von Zeilen enthält.Sie können andere Methoden zur Berechnung der Anzahl von N in meinen Post- Präfix-Indizes in MySQL lesen .
quelle
Ich habe diesen Fehler beim Hinzufügen eines Index zu einer Tabelle mit Textspalten erhalten. Sie müssen die Größe angeben, die Sie für jeden Texttyp verwenden möchten.
Setzen Sie den Größenbetrag in die Klammer ()
Wenn zu viele Bytes verwendet werden, können Sie in den Klammern eine Größe für varchar angeben, um die für die Indizierung verwendete Menge zu verringern. Dies gilt auch dann, wenn Sie eine Größe für einen Typ wie varchar (1000) angegeben haben. Sie müssen keine neue Tabelle erstellen, wie andere gesagt haben.
Index hinzufügen
Hinzufügen eines eindeutigen Index
quelle
HINWEIS : 767 ist die Anzahl der Zeichen, bis zu der MySQL Spalten indiziert, während es sich um Blob- / Textindizes handelt
Ref: http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html
quelle
Eine weitere hervorragende Möglichkeit, damit umzugehen, besteht darin, Ihr TEXT-Feld ohne die eindeutige Einschränkung zu erstellen und ein Geschwister-VARCHAR-Feld hinzuzufügen, das eindeutig ist und einen Digest (MD5, SHA1 usw.) des TEXT-Felds enthält. Berechnen und speichern Sie den Digest über das gesamte TEXT-Feld, wenn Sie das TEXT-Feld einfügen oder aktualisieren. Dann gibt es eine Eindeutigkeitsbeschränkung für das gesamte TEXT-Feld (und nicht für einen führenden Teil), die schnell durchsucht werden kann.
quelle
Keine langen Werte als Primärschlüssel. Das wird deine Leistung zerstören. Weitere Informationen finden Sie im MySQL-Handbuch, Abschnitt 13.6.13 'InnoDB-Leistungsoptimierung und Fehlerbehebung'.
Verwenden Sie stattdessen einen Ersatz-Int-Schlüssel als primären Schlüssel (mit auto_increment) und Ihren Loong-Schlüssel als sekundären EINZIGARTIGEN.
quelle
Fügen Sie eine weitere varChar (255) -Spalte hinzu (standardmäßig als leere Zeichenfolge nicht null), um den Überlauf zu halten, wenn 255 Zeichen nicht ausreichen, und ändern Sie diese PK, um beide Spalten zu verwenden. Dies klingt jedoch nicht nach einem gut gestalteten Datenbankschema, und ich würde empfehlen, dass ein Datenmodellierer überprüft, was Sie haben, um es für eine weitere Normalisierung umzugestalten.
quelle
Die Lösung für das Problem besteht darin, dass Sie in Ihrer
CREATE TABLE
Anweisung die Einschränkung hinzufügen können,UNIQUE ( problemtextfield(300) )
nachdem die Spalte Definitionen erstellt hat, um beispielsweise diekey
Länge der300
Zeichen für einTEXT
Feld anzugeben . Dann müssten die ersten300
Zeichen desproblemtextfield
TEXT
Feldes eindeutig sein, und alle Unterschiede danach würden ignoriert.quelle
Wenn Sie in diesem Feld einen Index verwenden möchten, sollten Sie außerdem die MyISAM-Speicher-Engine und den FULLTEXT-Indextyp verwenden.
quelle
Bisher hat es noch niemand erwähnt ... mit utf8mb4, das 4-Byte ist und auch Emoticons speichern kann (wir sollten nie mehr 3-Byte utf8 verwenden), und wir können Fehler vermeiden, da
Incorrect string value: \xF0\x9F\x98\...
wir nicht typisches VARCHAR (255) verwenden sollten , sondern VARCHAR ( 191) weil für den Fall, dass utf8mb4 und VARCHAR (255) derselbe Teil der Daten außerhalb der Seite gespeichert wird und Sie keinen Index für die Spalte VARCHAR (255) erstellen können, aber für VARCHAR (191). Dies liegt daran, dass die maximale indizierte Spaltengröße für ROW_FORMAT = COMPACT oder ROW_FORMAT = REDUNDANT 767 Byte beträgt.Für neuere Zeilenformate ROW_FORMAT = DYNAMIC oder ROW_FORMAT = COMPRESSED (für das ein neueres Dateiformat erforderlich ist innodb_file_format = Barracuda nicht älter Antelope) beträgt die maximale indizierte Spaltengröße 3072. Sie ist verfügbar, da MySQL> = 5.6.3, wenn innodb_large_prefix = 1 (standardmäßig deaktiviert für MySQL <= 5.7.6 und standardmäßig für MySQL aktiviert> = 5.7.7). In diesem Fall können wir also VARCHAR (768) für utf8mb4 (oder VARCHAR (1024) für altes utf8) für indizierte Spalten verwenden. Die Option innodb_large_prefix ist seit 5.7.7 veraltet, da ihr Verhalten in MySQL 8 integriert ist (in dieser Version ist die Option entfernt).
quelle
Sie müssen den Spaltentyp in
varchar
oderinteger
für die Indizierung ändern .quelle
Gehen Sie zu MySQL
edit table
-> ändern Sie den Spaltentyp invarchar(45)
.quelle
Verwenden Sie so
quelle