656 Stimmen

MySQL-Fehler #1071 - Der angegebene Schlüssel war zu lang; die maximale Schlüssellänge beträgt 767 Bytes

Wenn ich den folgenden Befehl ausführe:

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 über Spalte1 und Spalte2:

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

でしょう varchar(20) benötigt nur 21 Bytes, während varchar(500) benötigt nur 501 Bytes. Die Gesamtzahl der Bytes beträgt also 522, also weniger als 767. Warum habe ich dann die Fehlermeldung erhalten?

#1071 - Specified key was too long; max key length is 767 bytes

5 Stimmen

Da es sich nicht um 520 Bytes, sondern um 2080 Bytes handelt, die weit über 767 Bytes hinausgehen, könnten Sie Spalte1 varchar(20) und Spalte2 varchar(170) verwenden. Wenn Sie eine Zeichen/Byte-Entsprechung wünschen, verwenden Sie latin1

3 Stimmen

Ich denke, Ihre Berechnung ist ein bisschen falsch hier. mysql verwendet 1 oder 2 zusätzliche Bytes, um die Werte Länge aufzeichnen: 1 Byte, wenn die maximale Länge der Spalte 255 Bytes oder weniger ist, 2, wenn es länger als 255 Bytes ist. die utf8_general_ci Codierung benötigt 3 Bytes pro Zeichen so varchar (20) verwendet 61 Bytes, varchar (500) verwendet 1502 Bytes insgesamt 1563 Bytes

3 Stimmen

Mysql> select maxlen, character_set_name from information_schema.character_sets where character_set_name in('latin1', 'utf8', 'utf8mb4'); maxlen | character_set_name ------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4

23voto

Anthony Rutledge Punkte 5794
Specified key was too long; max key length is 767 bytes

Sie erhalten diese Meldung, weil 1 Byte nur dann einem Zeichen entspricht, wenn Sie die latin-1 Zeichensatz. Wenn Sie utf8 wird jedes Zeichen bei der Definition Ihrer Schlüsselspalte als 3 Bytes betrachtet. Wenn Sie utf8mb4 wird jedes Zeichen bei der Definition Ihrer Schlüsselspalte als 4 Byte betrachtet. Sie müssen also das Zeichenlimit Ihres Schlüsselfeldes mit 1, 3 oder 4 (in meinem Beispiel) multiplizieren, um die Anzahl der Bytes zu bestimmen, die das Schlüsselfeld zulässt. Wenn Sie uft8mb4 verwenden, können Sie nur 191 Zeichen für ein natives InnoDB-Primärschlüsselfeld definieren. Überschreiten Sie einfach nicht 767 Bytes.

20voto

Rick James Punkte 120626

5 Umgehungen:

Die Grenze wurde in 5.7.7 (MariaDB 10.2.2?) angehoben. Und es kann mit etwas Arbeit in 5.6 (10.1) erhöht werden.

Wenn Sie an die Grenze stoßen, weil Sie versuchen, den CHARACTER SET utf8mb4 zu verwenden. Dann führen Sie eine der folgenden Maßnahmen durch (jede hat einen Nachteil), um den Fehler zu vermeiden:

  Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this;
  Change 255 to 191 on the VARCHAR -- you lose any values longer than 191 characters (unlikely?);
  ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese;
  Use a "prefix" index -- you lose some of the performance benefits.
  Or... Stay with older version but perform 4 steps to raise the limit to 3072 bytes:

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;  -- (or COMPRESSED)

-- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes

17voto

diyism Punkte 11786

Sie könnten eine Spalte für den md5 von langen Spalten hinzufügen

0 Stimmen

Beachten Sie, dass Sie damit keine Bereichsabfragen über diese Spalten durchführen können. Präfixlängen auf VARCHARs ermöglichen es Ihnen, diese Eigenschaft beizubehalten, verursachen aber möglicherweise falsche Übereinstimmungen im Index (und Scannen und Zeilensuche, um sie zu eliminieren) (siehe die akzeptierte Antwort). (Dies ist im Wesentlichen ein manuell implementierter Hash-Index, den MysQL leider nicht mit InnoDB-Tabellen unterstützt).

0 Stimmen

Ich konnte keine Präfix-Indizes verwenden, weil ich zu Testzwecken die Kompatibilität mit H2 aufrechterhalten musste, und fand, dass die Verwendung einer Hash-Spalte gut funktioniert. Ich würde stark empfiehlt die Verwendung einer kollisionssicheren Funktion wie SHA1 anstelle von MD5, um zu verhindern, dass böswillige Benutzer Kollisionen erzeugen. Eine Indexkollision könnte ausgenutzt werden, um Daten zu verlieren, wenn eine Ihrer Abfragen nur den Hash-Wert und nicht den vollständigen Spaltenwert überprüft.

16voto

Für laravel 5.7 à 9.0

Zu befolgende Schritte

  1. Ir a App\Providers\AppServiceProvider.php .
  2. Dies zum Anbieter hinzufügen use Illuminate\Support\Facades\Schema; oben.
  3. Innerhalb der Boot-Funktion Folgendes hinzufügen Schema::defaultStringLength(191);

Genießen Sie das alles.

0 Stimmen

Funktioniert auch für Laravel 5.8.

0 Stimmen

Dies ist eine schlechte Lösung. Grund: Indizes sind nicht für eine unendliche Länge gedacht. Wenn Sie einen eindeutigen Index auf etwas anwenden, möchten Sie, dass der Index die meiste Zeit über einen festen Wert hat. Das bedeutet, dass Sie SOLLTE NICHT Sachen machen wie email einzigartig, aber Sie sollten die E-Mail hashen und sie 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 sich nicht skalieren lassen.

15voto

flik Punkte 3099

Ich habe dieses Problem mit :

varchar(200) 

ersetzt durch

varchar(191)

alle eindeutigen oder primären varchar-Schlüssel, die mehr als 200 haben, durch 191 ersetzen oder sie als Text festlegen.

0 Stimmen

Das hat bei mir auch funktioniert. Ich hatte ein varchar(250), aber die Daten waren nie so lang. Ich änderte es in varchar(100). Danke für die Idee :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X