Als ich den folgenden Befehl ausgeführt habe:
ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);
Ich habe diese Fehlermeldung erhalten:
#1071 - Specified key was too long; max key length is 767 bytes
Informationen zu Spalte1 und Spalte2:
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
Ich denke varchar(20)
, benötigt nur 21 Bytes, während varchar(500)
nur 501 Bytes benötigt. Die Gesamtzahl der Bytes beträgt also 522, weniger als 767. Warum habe ich die Fehlermeldung erhalten?
#1071 - Specified key was too long; max key length is 767 bytes
mysql
byte
varchar
mysql-error-1071
Steven
quelle
quelle
Antworten:
767 Byte ist die angegebene Präfixbeschränkung für InnoDB-Tabellen in MySQL Version 5.6 (und früheren Versionen). Es ist 1.000 Byte lang für MyISAM-Tabellen. In MySQL Version 5.7 und höher wurde diese Grenze auf 3072 Byte erhöht.
Sie müssen sich auch darüber im Klaren sein, dass Sie, wenn Sie einen Index für ein großes char- oder varchar-Feld festlegen, das utf8mb4-codiert ist, die maximale Indexpräfixlänge von 767 Bytes (oder 3072 Bytes) durch 4 teilen müssen, was zu 191 führt. Dies liegt daran Die maximale Länge eines utf8mb4-Zeichens beträgt vier Bytes. Für ein utf8-Zeichen wären es drei Bytes, was zu einer maximalen Indexpräfixlänge von 254 führt.
Eine Möglichkeit besteht darin, Ihre VARCHAR-Felder nur mit einer Untergrenze zu versehen.
Eine andere Option (entsprechend der Antwort auf dieses Problem ) besteht darin, die Teilmenge der Spalte und nicht den gesamten Betrag abzurufen, dh:
Optimieren Sie, wenn Sie den Schlüssel zum Anwenden benötigen, aber ich frage mich, ob es sich lohnt, Ihr Datenmodell in Bezug auf diese Entität zu überprüfen, um festzustellen, ob es Verbesserungen gibt, mit denen Sie die beabsichtigten Geschäftsregeln implementieren können, ohne die MySQL-Einschränkung zu treffen.
quelle
utf8mb4
Zeichensatz von MySQL (den der Rest der Welt utf8 nennt) (höchstens) 4 Bytes pro Zeichen benötigt , können Sie nur bis zu indizierenVARCHAR(191)
. Mysqlsutf8
Zeichensatz (den der Rest der Welt als kaputt bezeichnet) benötigt höchstens 3 Bytes pro Zeichen. Wenn Sie diesen verwenden (was Sie nicht sollten ), können Sie bis zuVARCHAR(255)
Wenn jemand Probleme mit INNODB / Utf-8 hat, die versuchen, einen
UNIQUE
Index für einVARCHAR(256)
Feld zu erstellen , wechseln Sie zuVARCHAR(255)
. Es scheint, 255 ist die Einschränkung.quelle
3*255 = 765 < 767
.utf8
, die leider gebrochen. Es können nur Zeichen in der mehrsprachigen Grundebene codiert werden. Sie werden Probleme mit Charakteren bekommen, die außerhalb davon liegen. Zum Beispiel fallen die Emoji-Charaktere, die sie hinzugefügt haben, meiner Meinung nach nicht dazu. Anstatt zuVARCHAR(255)
wechseln, wechseln Sie zuVARCHAR(191)
und wechseln Sie die Codierung zuutf8mb4
(was eigentlich nur utf8 ist, aber MySql wollte zurückhalten. Kompatibel).Wenn Sie das Limit erreichen. Stellen Sie Folgendes ein.
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
quelle
utf8mb4
Limit (die am häufigsten verwendete Codierung für neuere Datenbanken, da sie Emojis / etc akzeptiert).ENGINE=InnoDB DEFAULT CHARSET=utf8
am Ende derCREATE TABLE
Anweisung angegeben, dass ich einenVARCHAR(255)
Primärschlüssel haben konnte . Vielen Dank.MySQL geht vom schlechtesten Fall für die Anzahl der Bytes pro Zeichen in der Zeichenfolge aus. Für die MySQL-Codierung 'utf8' sind das 3 Bytes pro Zeichen, da diese Codierung keine darüber hinausgehenden Zeichen zulässt
U+FFFF
. Für die MySQL-Codierung 'utf8mb4' sind es 4 Bytes pro Zeichen, da MySQL dies als tatsächliches UTF-8 bezeichnet.Angenommen, Sie verwenden 'utf8', benötigt Ihre erste Spalte 60 Byte des Index und Ihre zweite weitere 1500 Byte.
quelle
Führen Sie diese Abfrage vor Ihrer Abfrage aus:
Dies erhöht die Grenze auf
3072 bytes
.quelle
innodb_file_format
muss seinBARRACUDA
und auf Tabellenebene muss manROW_FORMAT=DYNAMIC
oder verwendenROW_FORMAT=COMPRESSED
. Siehe den Kommentar von @ cwd oben mit der Anleitung.Lösung für Laravel Framework
Gemäß Laravel 5.4 * Dokumentation. ; Sie müssen die Standardzeichenfolgenlänge in der
boot
Methode derapp/Providers/AppServiceProvider.php
Datei wie folgt festlegen :Erläuterung dieses Fixes in Laravel 5.4. * Dokumentation :
quelle
Welche Zeichenkodierung verwenden Sie? Einige Zeichensätze (wie UTF-16 usw.) verwenden mehr als ein Byte pro Zeichen.
quelle
20 * 4 + 1
Bytes und die Spalte mit 500 Zeichen500 * 4 + 2
Bytes sindVARCHAR(256)
Spalte mit einemUNIQUE
Index hatte das Ändern der Sortierung für mich keine Auswirkung, wie dies bei @Andresch der Fall war. Die Reduzierung der Länge von 256 auf 255 hat es jedoch gelöst. Ich verstehe nicht warum, da 767 / max 4 Bytes pro Zeichen maximal 191 ergeben würden?255*3 = 765; 256*3 = 768
. Es scheint, dass Ihr Server 3 Bytes pro Zeichen angenommen hat, @ArjanUTF8 benötigt 3 Byte pro Zeichen der Zeichenfolge zu speichern, so dass in Ihrem Fall 20 + 500 Zeichen = 20 * 3 + 500 * 3 = 1560 Bytes , die sich mehr als erlaubt 767 Bytes.
Das Limit für UTF8 liegt bei 767/3 = 255 Zeichen , für UTF8mb4, das 4 Bytes pro Zeichen verwendet, bei 767/4 = 191 Zeichen.
Es gibt zwei Lösungen für dieses Problem, wenn Sie eine längere Spalte als das Limit verwenden müssen:
In meinem Fall musste ich einen eindeutigen Index für eine Spalte hinzufügen, die eine SEO-Artikelzeichenfolge enthält, da ich nur
[A-z0-9\-]
Zeichen für SEO verwende,latin1_general_ci
die nur ein Byte pro Zeichen verwendet Die Spalte kann also eine Länge von 767 Bytes haben.Die andere Option für mich bestand darin, eine weitere Spalte zu erstellen, in der SEO-Hash gespeichert wird. Diese Spalte enthält den
UNIQUE
Schlüssel, um sicherzustellen, dass die SEO-Werte eindeutig sind. Ich würde auch einenKEY
Index zur ursprünglichen SEO-Spalte hinzufügen , um das Nachschlagen zu beschleunigen.quelle
Die Antwort, warum Sie eine Fehlermeldung erhalten, wurde bereits von vielen Benutzern hier beantwortet. In meiner Antwort geht es darum, wie man es repariert und so verwendet, wie es ist.
Siehe von diesem Link .
use my_database_name;
set global innodb_large_prefix=on;
set global innodb_file_format=Barracuda;
Das Problem dieses Fixes besteht darin, dass Sie db auf einen anderen Server exportieren (z. B. von localhost auf einen echten Host) und die MySQL-Befehlszeile auf diesem Server nicht verwenden können. Sie können es dort nicht zum Laufen bringen.
quelle
Sie haben diese Nachricht erhalten, weil 1 Byte nur dann 1 Zeichen entspricht, wenn Sie den
latin-1
Zeichensatz verwenden. Wenn Sie verwendenutf8
, wird jedes Zeichen bei der Definition Ihrer Schlüsselspalte als 3 Byte betrachtet. Wenn Sie verwendenutf8mb4
, wird jedes Zeichen bei der Definition Ihrer Schlüsselspalte als 4 Byte betrachtet. Daher müssen Sie die Zeichenbeschränkung Ihres Schlüsselfelds mit 1, 3 oder 4 (in meinem Beispiel) multiplizieren, um die Anzahl der Bytes zu bestimmen, die das Schlüsselfeld zulassen möchte. Wenn Sie uft8mb4 verwenden, können Sie nur 191 Zeichen für ein natives InnoDB-Primärschlüsselfeld definieren. Nur nicht 767 Bytes verletzen.quelle
Sie können eine Spalte des MD5 von langen Spalten hinzufügen
quelle
Ersetzen Sie
utf8mb4
mitutf8
in der Importdatei.quelle
Dieses Problem trat auf, als versucht wurde, einem VARCHAR (255) -Feld mit utf8mb4 einen EINZIGARTIGEN Index hinzuzufügen. Während das Problem hier bereits gut umrissen ist, wollte ich einige praktische Ratschläge hinzufügen, wie wir dies herausgefunden und gelöst haben.
Bei Verwendung von utf8mb4 zählen Zeichen als 4 Bytes, während sie unter utf8 als 3 Bytes gelten können. InnoDB-Datenbanken haben ein Limit, dass Indizes nur 767 Bytes enthalten dürfen. Wenn Sie utf8 verwenden, können Sie 255 Zeichen (767/3 = 255) speichern. Mit utf8mb4 können Sie jedoch nur 191 Zeichen (767/4 = 191) speichern.
VARCHAR(255)
Mit utf8mb4 können Sie durchaus reguläre Indizes für Felder hinzufügen. Die Indexgröße wird jedoch automatisch auf 191 Zeichen gekürzt - wieunique_key
hier:Dies ist in Ordnung, da reguläre Indizes nur verwendet werden, um MySQL dabei zu unterstützen, Ihre Daten schneller zu durchsuchen. Das gesamte Feld muss nicht indiziert werden.
Warum schneidet MySQL den Index für reguläre Indizes automatisch ab, gibt jedoch einen expliziten Fehler aus, wenn Sie versuchen, dies für eindeutige Indizes zu tun? Damit MySQL herausfinden kann, ob der eingefügte oder aktualisierte Wert bereits vorhanden ist, muss der gesamte Wert indiziert werden und nicht nur ein Teil davon.
Wenn Sie am Ende des Tages einen eindeutigen Index für ein Feld haben möchten, muss der gesamte Inhalt des Felds in den Index passen. Für utf8mb4 bedeutet dies, dass Sie Ihre VARCHAR-Feldlängen auf 191 Zeichen oder weniger reduzieren. Wenn Sie für diese Tabelle oder dieses Feld nicht utf8mb4 benötigen, können Sie es auf utf8 zurücksetzen und Ihre Felder mit einer Länge von 255 behalten.
quelle
Hier ist meine ursprüngliche Antwort:
Es funktioniert jedoch nicht in allen Fällen.
Es ist tatsächlich ein Problem, Indizes für VARCHAR-Spalten mit dem Zeichensatz
utf8
(oderutf8mb4
) zu verwenden, wobei VARCHAR-Spalten mehr als eine bestimmte Länge von Zeichen haben. Im Fall vonutf8mb4
beträgt diese bestimmte Länge 191.Weitere Informationen zur Verwendung langer Indizes in der MySQL-Datenbank finden Sie im Abschnitt "Langer Index" in diesem Artikel: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- Zeichensatz-zu-utf8mb4
quelle
5 Problemumgehungen:
Das Limit wurde in 5.7.7 (MariaDB 10.2.2?) Erhöht. Und es kann mit etwas Arbeit in 5.6 (10.1) erhöht werden.
Wenn Sie das Limit erreichen, weil Sie versuchen, CHARACTER SET utf8mb4 zu verwenden. Führen Sie dann einen der folgenden Schritte aus (jeder hat einen Nachteil), um den Fehler zu vermeiden:
- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes
quelle
Ich habe dieses Problem behoben mit:
Ersetzt mit
Alle Varchar, die mehr als 200 haben, ersetzen sie durch 191 oder setzen sie als Text.
quelle
Ich habe nach diesem Thema gesucht und endlich eine benutzerdefinierte Änderung erhalten
Für die MySQL Workbench 6.3.7 Version ist eine grafische Zwischenphase verfügbar
Für Versionen unter 6.3.7 sind keine direkten Optionen verfügbar, daher muss die Eingabeaufforderung verwendet werden
quelle
set global innodb_default_row_format = DYNAMIC;
Meldung angezeigt: FEHLER 1193 (HY000): Unbekannte Systemvariable 'innodb_default_row_format'Für Laravel 5.7 bis 6.0
Schritte zu folgen
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
oben hinzu.Schema::defaultStringLength(191);
das alles, viel Spaß.
quelle
email
einzigartig, aber Sie sollten die E - Mail - Hash und ein einzigartig machen. Im Gegensatz zu rohen String-Daten haben Hashes eine feste Breite und können ohne Probleme indiziert und eindeutig gemacht werden. Anstatt das Problem zu verstehen, verbreiten Sie schreckliche Praktiken, die nicht skalierbar sind.Ändern Sie Ihre Sortierung. Sie können utf8_general_ci verwenden , das fast alle unterstützt
quelle
Nur beim Erstellen von Tabellen zu wechseln
utf8mb4
,utf8
löste mein Problem. Zum Beispiel:CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
bisCREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
.quelle
Um das zu beheben, funktioniert das für mich wie ein Zauber.
quelle
Basierend auf der unten angegebenen Spalte verwenden diese beiden Spalten mit variablen Zeichenfolgen eine
utf8_general_ci
Sortierung (utf8
Zeichensatz ist impliziert).In MySQL
utf8
verwendet charset maximal 3 Bytes für jedes Zeichen. Daher müsste es 500 * 3 = 1500 Bytes zuweisen, was viel größer ist als die 767 Bytes, die MySQL zulässt. Deshalb wird dieser 1071-Fehler angezeigt.Mit anderen Worten, Sie müssen die Zeichenanzahl basierend auf der Bytedarstellung des Zeichensatzes berechnen, da nicht jeder Zeichensatz eine Einzelbyte-Darstellung ist (wie Sie angenommen haben). IE
utf8
in MySQL verwendet höchstens 3 Byte pro Zeichen, 767/3≈255 Zeichen und fürutf8mb4
eine höchstens 4-Byte-Darstellung 767 / 4≈191 Zeichen.Es ist auch bekannt, dass MySQL
quelle
Ich fand diese Abfrage hilfreich, um festzustellen, welche Spalten einen Index hatten, der die maximale Länge verletzte:
quelle
Bitte überprüfen Sie, ob dies der Fall
sql_mode
istWenn dies der Fall ist, wechseln Sie zu
ODER
Starten Sie Ihren Server neu und ändern Sie Ihre my.cnf-Datei.
quelle
In meinem Fall hatte ich dieses Problem, als ich eine Datenbank mit den Ausgabe- / Eingabezeichen für die Linux-Umleitung sicherte. Daher ändere ich die Syntax wie unten beschrieben. PS: mit einem Linux- oder Mac-Terminal.
Backup (ohne die> Weiterleitung)
Wiederherstellen (ohne die <Weiterleitung)
Der Fehler "Angegebener Schlüssel war zu lang; maximale Schlüssellänge beträgt 767 Bytes" ist einfach verschwunden.
quelle
Indexlängen & MySQL / MariaDB
Laravel verwendet standardmäßig den Zeichensatz utf8mb4 , der die Speicherung von "Emojis" in der Datenbank unterstützt. Wenn Sie eine Version von MySQL ausführen, die älter als die Version 5.7.7 oder MariaDB älter als die Version 10.2.2 ist, müssen Sie möglicherweise die durch Migrationen generierte Standardzeichenfolgenlänge manuell konfigurieren, damit MySQL Indizes für sie erstellt. Sie können dies konfigurieren, indem Sie die Schema :: defaultStringLength- Methode in Ihrem AppServiceProvider aufrufen:
Alternativ können Sie die Option innodb_large_prefix für Ihre Datenbank aktivieren. Anweisungen zum ordnungsgemäßen Aktivieren dieser Option finden Sie in der Dokumentation Ihrer Datenbank.
Referenz aus dem Blog: https://www.scratchcode.io/specified-key-too-long-error-in-laravel/
Referenz aus der offiziellen Laravel-Dokumentation: https://laravel.com/docs/5.7/migrations
quelle
Wenn Sie etwas erstellen wie:
es sollte so etwas sein
Sie müssen jedoch die Eindeutigkeit dieser Spalte anhand des Codes überprüfen oder eine neue Spalte als MD5 oder SHA1 der varchar-Spalte hinzufügen
quelle
Aufgrund von Präfixbeschränkungen tritt dieser Fehler auf. 767 Byte ist die angegebene Präfixbeschränkung für InnoDB-Tabellen in MySQL-Versionen vor 5.7. Es ist 1.000 Byte lang für MyISAM-Tabellen. In MySQL Version 5.7 und höher wurde diese Grenze auf 3072 Byte erhöht.
Wenn Sie für den Dienst, der Ihnen den Fehler gibt, Folgendes ausführen, sollte das Problem behoben sein. Dies muss in der MYSQL-CLI ausgeführt werden.
quelle
Ändern Sie CHARSET des beschwerdeführenden Indexfelds in "latin1",
dh ALTER TABLE tbl CHANGE myfield myfield varchar (600) CHARACTER SET latin1 DEFAULT NULL;
latin1 benötigt ein Byte für ein Zeichen anstelle von vier
quelle
Wenn Sie
innodb_log_file_size
kürzlich Änderungen vorgenommen haben , versuchen Sie, den vorherigen Wert wiederherzustellen, der funktioniert hat.quelle