Wenn 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 Gesamtbytes sind also 522, also weniger als 767. Warum wurde die Fehlermeldung angezeigt?
#1071 - Specified key was too long; max key length is 767 bytes
767 Byte ist der angegebene Präfixeinschrä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 auch wissen, dass Sie, wenn Sie einen Index für ein großes char- oder varchar-Feld festlegen, das utf8mb4-codiert ist, die maximale Index-Präfixlänge von 767 Byte (oder 3072 Byte) durch 4 dividieren müssen, was zu 191 führt Die maximale Länge eines utf8mb4-Zeichens beträgt vier Bytes. Für ein utf8-Zeichen wären das drei Bytes, was zu einer Länge des Index-Präfixes von maximal 254 führt.
Eine Möglichkeit besteht darin, Ihre VARCHAR-Felder einfach unterer Grenzwert zu setzen.
Eine andere Option (entsprechend der Antwort auf dieses Problem ) besteht darin, die Teilmenge der Spalte und nicht die gesamte Menge abzurufen, d. H .:
ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );
Wenn Sie den Schlüssel anwenden müssen, müssen Sie den Schlüssel anwenden, aber ich frage mich, ob es sich lohnt, Ihr Datenmodell bezüglich dieser Entität zu überprüfen, um zu sehen, ob es Verbesserungen gibt, mit denen Sie die beabsichtigten Geschäftsregeln implementieren können, ohne die MySQL-Einschränkung zu treffen.
Wenn jemand Probleme mit INNODB/Utf-8 hat und versucht, einen UNIQUE
-Index in ein VARCHAR(256)
-Feld zu setzen, wechseln Sie zu VARCHAR(255)
. Es scheint, 255 ist die Einschränkung.
Wenn du das Limit erreicht hast. Stellen Sie Folgendes ein.
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
MySQL nimmt den ungünstigsten Fall für die Anzahl der Bytes pro Zeichen in der Zeichenfolge an. Für die MySQL-Kodierung 'utf8' sind dies 3 Byte pro Zeichen, da diese Kodierung keine Zeichen außerhalb von U+FFFF
zulässt. Für die MySQL-Codierung 'utf8mb4' sind dies 4 Byte pro Zeichen, da MySQL dies als UTF-8 bezeichnet.
Wenn Sie also 'utf8' verwenden, nimmt die erste Spalte 60 Bytes des Index und die zweite Spalte weitere 1500.
führen Sie diese Abfrage vor Ihrer Abfrage aus:
SET @@global.innodb_large_prefix = 1;
das Limit wird auf 3072 bytes
erhöht.
Welche Zeichenkodierung verwenden Sie? Einige Zeichensätze (wie UTF-16 usw.) verwenden mehr als ein Byte pro Zeichen.
Lösung für Laravel Framework
Gemäß Laravel 5.4. * Dokumentation ; Sie müssen die Standardzeichenfolgenlänge in der boot
-Methode der app/Providers/AppServiceProvider.php
-Datei wie folgt festlegen:
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
Erklärung zu diesem Fix, gegeben von Laravel 5.4. * Documentation :
Laravel verwendet standardmäßig den Zeichensatz
utf8mb4
, der die Speicherung von "Emojis" in der Datenbank unterstützt. Wenn Sie eine ältere MySQL-Version als 5.7.7 oder eine ältere MariaDB-Version als 10.2.2 ausführen, müssen Sie möglicherweise die von Migrationen generierte Standardzeichenfolgenlänge manuell konfigurieren, damit MySQL Indizes für sie erstellt. Sie können dies konfigurieren, indem Sie dieSchema::defaultStringLength
-Methode in IhrerAppServiceProvider
aufrufen.Alternativ können Sie die
innodb_large_prefix
-Option für Ihr .__ aktivieren. Datenbank. Anweisungen zu .__ finden Sie in der Dokumentation Ihrer Datenbank. So aktivieren Sie diese Option.
Ich denke, dass varchar (20) nur 21 Bytes benötigt, während varchar (500) nur erfordert 501 Bytes. Die Gesamtbytes sind also 522, also weniger als 767. Warum also Habe ich die Fehlermeldung erhalten?
UTF8 benötigt 3 Byte pro Zeichen , um die Zeichenfolge zu speichern. In Ihrem Fall sind also 20 + 500 Zeichen = 20 * 3 + 500 * 3 = 1560 Bytes, was mehr als Allowed 767 ist bytes.
Die Grenze für UTF8 ist 767/3 = 255 Zeichen , für UTF8mb4, die 4 Byte pro Zeichen verwendet, sind dies 767/4 = 191 Zeichen.
[A-z0-9\-]
-Zeichen für SEO verwende, habe ich latin1_general_ci
verwendet, der nur ein Byte pro Zeichen verwendet. Die Spalte kann also 767 Byte lang sein. UNIQUE
, um sicherzustellen, dass die SEO-Werte eindeutig sind. Ich würde auch KEY
index zur ursprünglichen SEO-Spalte hinzufügen, um das Nachschlagen zu beschleunigen.Specified key was too long; max key length is 767 bytes
Sie haben diese Nachricht erhalten, da 1 Byte nur 1 Zeichen entspricht, wenn Sie den latin-1
-Zeichensatz verwenden. Wenn Sie utf8
verwenden, wird jedes Zeichen bei der Definition Ihrer Schlüsselspalte als 3 Byte betrachtet. Wenn Sie utf8mb4
verwenden, wird jedes Zeichen bei der Definition Ihrer Schlüsselspalte als 4 Byte betrachtet. Daher müssen Sie das Zeichenlimit Ihres Schlüsselfelds 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 systemeigenes InnoDB-Primärschlüsselfeld definieren. Verletzen Sie einfach nicht 767 Bytes.
Die Antwort, warum Sie eine Fehlermeldung erhalten, wurde hier bereits von vielen Benutzern beantwortet. In meiner Antwort geht es darum, wie man es repariert und wie es ist.
Verweisen Sie von diesem Link .
use my_database_name;
Datenbank geändert
set global innodb_large_prefix=on;
Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)
set global innodb_file_format=Barracuda;
Abfrage OK, 0 Zeilen betroffen (0,02 Sek.)
Das Problem dieses Fixes ist, wenn Sie db auf einen anderen Server exportieren (z. B. von localhost auf einen echten Host) und Sie die MySQL-Befehlszeile nicht auf diesem Server verwenden können. Sie können es dort nicht zum Laufen bringen.
sie können eine Spalte des MD5 langer Spalten hinzufügen
Dieses Problem ist aufgetreten, als versucht wurde, mithilfe von utf8mb4 einen UNIQUE-Index zu einem VARCHAR-Feld (255) hinzuzufügen. Während das Problem hier bereits gut umrissen ist, wollte ich ein paar praktische Ratschläge hinzufügen, wie wir dies herausgefunden und gelöst haben.
Bei Verwendung von utf8mb4 zählen die Zeichen als 4 Bytes, während sie unter utf8 als 3 Bytes gelten könnten. InnoDB-Datenbanken haben ein Limit, dass Indizes nur 767 Bytes enthalten dürfen. Wenn Sie utf8 verwenden, können Sie 255 Zeichen speichern (767/3 = 255), aber bei utf8mb4 können Sie nur 191 Zeichen speichern (767/4 = 191).
Sie können absolut reguläre Indizes für VARCHAR(255)
-Felder mit utf8mb4 hinzufügen. Die Indexgröße wird jedoch automatisch auf 191 Zeichen gekürzt - wie hier unique_key
:
Dies ist in Ordnung, da reguläre Indizes nur dazu dienen, MySQL dabei zu unterstützen, Ihre Daten schneller zu durchsuchen. Das gesamte Feld muss nicht indiziert werden.
Warum schneidet MySQL den Index automatisch für reguläre Indizes ab, gibt jedoch einen expliziten Fehler aus, wenn versucht wird, dies für eindeutige Indizes zu tun? Damit MySQL herausfinden kann, ob der Wert, der bereits eingefügt oder aktualisiert wird, bereits vorhanden ist, muss es den gesamten Wert indizieren und nicht nur einen 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 die Länge Ihrer VARCHAR-Felder auf 191 Zeichen oder weniger reduzieren. Wenn Sie utf8mb4 nicht für diese Tabelle oder dieses Feld benötigen, können Sie es wieder auf utf8 ablegen und Ihre 255 Längenfelder beibehalten.
Hier ist meine ursprüngliche Antwort:
Ich lasse die Datenbank einfach fallen und erstellt sie neu, und der Fehler ist weg:
drop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;
Es funktioniert jedoch nicht in allen Fällen.
Es ist tatsächlich ein Problem, Indizes für VARCHAR-Spalten mit dem Zeichensatz utf8
(oder utf8mb4
) zu verwenden, wobei VARCHAR-Spalten mehr als eine bestimmte Zeichenlänge haben. Im Fall von utf8mb4
beträgt diese bestimmte Länge 191.
Weitere Informationen zur Verwendung langer Indizes in der MySQL-Datenbank finden Sie in diesem Artikel im Abschnitt "Long Index": http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql- Datenbankzeichensatz-to-utf8mb4
Ich habe einige Suchanfragen zu diesem Thema gemacht und endlich einige benutzerdefinierte Änderungen erhalten
Für MySQL Workbench 6.3.7 Version Grafische Interphase ist verfügbar
Für Versionen unter 6.3.7 sind keine direkten Optionen verfügbar, daher muss der Befehl Prompt verwendet werden.
Ändern Sie Ihre Kollatierung. Sie können utf8_general_ci verwenden, das fast alle unterstützt
Ich habe dieses Problem behoben mit:
varchar(200)
ersetzt mit
varchar(191)
alle Varchar, die mehr als 200 haben, ersetzen sie durch 191 oder setzen sie als Text.
5 Problemumgehungen:
Das Limit 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 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:
⚈ 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
Das Ändern von utf8mb4
in utf8
beim Erstellen von Tabellen hat mein Problem gelöst. Zum Beispiel: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
bis CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
.
Für Laravel 5.7 oder 5.6
Schritte zu folgen
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
in der Liste hinzu.Schema::defaultStringLength(191);
hinzudas alles genießt.
Basierend auf der unten angegebenen Spalte verwenden diese 2 Variablenstringspalten die utf8_general_ci
-Sortierung (utf8
-Zeichensatz ist impliziert).
In MySQL verwendet utf8
charset für jedes Zeichen maximal 3 Byte . Daher müsste 500 * 3 = 1500 Bytes zugewiesen werden, was viel größer ist als die von MySQL zulässigen 767 Bytes. Deshalb erhalten Sie diesen 1071-Fehler.
Mit anderen Worten, Sie müssen die Zeichenanzahl basierend auf der Bytendarstellung des Zeichensatzes berechnen, da nicht jeder Zeichensatz eine Einzelbyterepräsentation ist (wie Sie annehmen.) I.E. utf8
verwendet in MySQL höchstens 3 Byte pro Zeichen, 767/3≈255 Zeichen und für utf8mb4
eine maximal 4-Byte-Darstellung 767/4≈191 Zeichen.
Es ist auch bekannt, dass MySQL
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
In meinem Fall hatte ich dieses Problem, als ich eine Datenbank mit den Ausgabe-/Eingabezeichen der Linux-Umleitung gesichert hatte. Daher ändere ich die Syntax wie unten beschrieben. PS: mit einem Linux- oder Mac-Terminal.
Backup (ohne die> Weiterleitung)
# mysqldump -u root -p databasename -r bkp.sql
Wiederherstellen (ohne <Weiterleitung)
# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql
Der Fehler "Angegebener Schlüssel war zu lang; maximale Schlüssellänge beträgt 767 Byte", ist einfach verschwunden.
Ich fand diese Abfrage hilfreich, um herauszufinden, welche Spalten einen Index haben, der die maximale Länge verletzt:
SELECT
c.TABLE_NAME As TableName,
c.COLUMN_NAME AS ColumnName,
c.DATA_TYPE AS DataType,
c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
ON s.table_name = c.TABLE_NAME
AND s.COLUMN_NAME = c.COLUMN_NAME
WHERE c.TABLE_SCHEMA = DATABASE()
AND c.CHARACTER_MAXIMUM_LENGTH > 191
AND c.DATA_TYPE IN ('char', 'varchar', 'text')
Bitte überprüfen Sie, ob sql_mode
so ist
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
wenn ja, wechseln Sie zu
sql_mode=NO_ENGINE_SUBSTITUTION
OR
starten Sie Ihren Server neu und ändern Sie Ihre my.cnf-Datei (Putting folgend)
innodb_large_prefix=on
Aufgrund von Präfixeinschränkungen tritt dieser Fehler auf. 767 Byte ist die angegebene Präfixeinschrä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 den folgenden Dienst für den Fehler ausführen, sollte der Fehler behoben werden. Dies muss in der MYSQL-CLI ausgeführt werden.
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;
Ändern Sie CHARSET des Reklamationsindexfelds in "latin1".
ALTER TABLE tbl CHANGE myfield myfield varchar (600) ZEICHENSATZ latin1 DEFAULT NULL;
latin1 benötigt ein Byte statt vier Zeichen
5 Problemumgehungen
Dieses Problem trat auf, bevor das Limit in 5.7.7 (MariaDB 10.2.2?) Angehoben wurde.
Wenn Sie die Grenze überschreiten, 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:
VARCHAR
- Sie verlieren alle Werte, die länger als 191 Zeichen sind (unwahrscheinlich?).ALTER .. CONVERT TO utf8
- Sie verlieren Emoji und einige Chinesen;Oder ... Bleibe bei 5.6/5.5/10.1, aber führe 4 Schritte aus, um das Limit auf 3072 Bytes zu erhöhen:
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)
Um das zu beheben, funktioniert das für mich wie ein Zauber.
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
Wenn Sie etwas erstellen:
CREATE TABLE IF NOT EXISTS your_table (
id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar(256) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;
es sollte so etwas sein
CREATE TABLE IF NOT EXISTS your_table (
id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar(256) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;
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
Indexlängen & MySQL/MariaDB
Laravel verwendet standardmäßig das Zeichen utf8mb4, das die Speicherung von "emojis" in der Datenbank unterstützt. Wenn Sie eine ältere MySQL-Version als 5.7.7 oder eine ältere MariaDB-Version als 10.2.2 ausführen, müssen Sie möglicherweise die von Migrationen generierte Standardzeichenfolgenlänge manuell konfigurieren, damit MySQL Indizes für sie erstellt. Sie können dies konfigurieren, indem Sie die Methode Schema :: defaultStringLength in Ihrem AppServiceProvider: aufrufen.
use Illuminate\Support\Facades\Schema;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
Alternativ können Sie mit die Option innodb_large_prefix für Ihre Datenbank aktivieren. Anweisungen zur korrekten Aktivierung dieser Option finden Sie in der Dokumentation Ihrer Datenbank.
Referenz aus der offiziellen Laravel-Dokumentation:https://laravel.com/docs/5.7/migrations