Kiedy wykonałem następujące polecenie:
ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);
Otrzymałem ten komunikat o błędzie:
#1071 - Specified key was too long; max key length is 767 bytes
Informacje o kolumnie 1 i kolumnie 2:
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
Myślę, że varchar(20)
wymaga tylko 21 bajtów, a varchar(500)
tylko 501 bajtów. Więc łączna liczba bajtów to 522, mniej niż 767. Dlaczego więc dostałem komunikat o błędzie?
#1071 - Specified key was too long; max key length is 767 bytes
mysql
byte
varchar
mysql-error-1071
Steven
źródło
źródło
Odpowiedzi:
767 bajtów to podane ograniczenie prefiksu dla tabel InnoDB w MySQL w wersji 5.6 (i wcześniejszych wersjach). Dla tabel MyISAM ma 1000 bajtów. W MySQL w wersji 5.7 i wyższych limit ten został zwiększony do 3072 bajtów.
Musisz także pamiętać, że jeśli ustawisz indeks na duże pole char lub varchar, które jest zakodowane w utf8mb4, musisz podzielić maksymalną długość prefiksu indeksu wynoszącą 767 bajtów (lub 3072 bajtów) przez 4, co daje wynik 191. Jest tak, ponieważ maksymalna długość znaku utf8mb4 wynosi cztery bajty. Dla znaku utf8 byłyby to trzy bajty, co daje maksymalną długość prefiksu indeksu 254.
Jedną z opcji jest po prostu dolny limit na polach VARCHAR.
Inną opcją (zgodnie z odpowiedzią na ten problem ) jest uzyskanie podzbioru kolumny zamiast całej kwoty, tj .:
Dostosuj, aby uzyskać klucz do zastosowania, ale zastanawiam się, czy warto byłoby przejrzeć model danych dotyczący tego podmiotu, aby sprawdzić, czy istnieją ulepszenia, które pozwoliłyby na wdrożenie zamierzonych reguł biznesowych bez naruszania ograniczeń MySQL.
źródło
utf8mb4
zestaw znaków Mysql (który reszta świata nazywa utf8) potrzebuje (maksymalnie) 4 bajtów na znak , można indeksować tylko doVARCHAR(191)
.utf8
Zestaw znaków Mysql (który reszta świata nazywa uszkodzonymi) potrzebuje maksymalnie 3 bajtów na znak, więc jeśli go używasz (czego nie powinieneś ), możesz indeksować doVARCHAR(255)
Jeśli ktoś ma problemy z INNODB / Utf-8 próbującym umieścić
UNIQUE
indeks wVARCHAR(256)
polu, przełącz go naVARCHAR(255)
. Wydaje się, że 255 jest ograniczeniem.źródło
3*255 = 765 < 767
.utf8
, który niestety jest zepsuty. Może kodować tylko znaki w podstawowej płaszczyźnie wielojęzycznej. Pojawią się problemy z postaciami, które będą poza tym. Na przykład te znaki Emoji, które dodają, są poza tym, jak sądzę. Więc zamiast przełączać się naVARCHAR(255)
, przełącz się naVARCHAR(191)
i przełącz kodowanie nautf8mb4
(co w rzeczywistości jest po prostu utf8, ale MySql chciał się wycofać.Kiedy osiągniesz limit. Ustaw następujące.
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
źródło
utf8mb4
rzeczy, a także zawiera limit (który jest najczęściej używanym kodowaniem w nowszych bazach danych, ponieważ akceptuje emoji / etc).ENGINE=InnoDB DEFAULT CHARSET=utf8
na końcuCREATE TABLE
instrukcji, że mogłem miećVARCHAR(255)
klucz podstawowy. Dzięki.MySQL zakłada najgorszy przypadek liczby bajtów na znak w ciągu. W przypadku kodowania MySQL „utf8” jest to 3 bajty na znak, ponieważ kodowanie to nie dopuszcza znaków poza nim
U+FFFF
. W przypadku kodowania „utf8mb4” MySQL jest to 4 bajty na znak, ponieważ tak właśnie MySQL nazywa rzeczywisty UTF-8.Zakładając, że używasz „utf8”, twoja pierwsza kolumna zajmie 60 bajtów indeksu, a druga następna 1500.
źródło
uruchom to zapytanie przed zapytaniem:
zwiększy to limit do
3072 bytes
.źródło
innodb_file_format
musi byćBARRACUDA
i Na poziomie stołu musisz użyćROW_FORMAT=DYNAMIC
lubROW_FORMAT=COMPRESSED
. Zobacz komentarz @ cwd powyżej z przewodnikiem.Rozwiązanie dla Laravel Framework
Zgodnie z dokumentacją Laravel 5.4. * ; Musisz ustawić domyślną długość ciągu w
boot
metodzieapp/Providers/AppServiceProvider.php
pliku w następujący sposób:Wyjaśnienie tej poprawki podane w dokumentacji Laravel 5.4. * :
źródło
Jakiego kodowania znaków używasz? Niektóre zestawy znaków (jak UTF-16 i tak dalej) używają więcej niż jednego bajtu na znak.
źródło
20 * 4 + 1
bajty, a kolumna 500 znaków to500 * 4 + 2
bajtyVARCHAR(256)
kolumny zUNIQUE
indeksem zmiana sortowania nie miała dla mnie żadnego efektu, tak jak w przypadku @Andresch. Jednak zmniejszenie długości z 256 do 255 to rozwiązało. Nie rozumiem dlaczego, ponieważ 767 / maks. 4 bajty na znak dają maksymalnie 191?255*3 = 765; 256*3 = 768
. Wygląda na to, że twój serwer przypisywał 3 bajty na znak, @ArjanUTF8 wymaga 3 bajtów na znak do przechowywania łańcucha, więc w twoim przypadku 20 + 500 znaków = 20 * 3 + 500 * 3 = 1560 bajtów, co jest więcej niż dozwolone 767 bajtów.
Limit dla UTF8 wynosi 767/3 = 255 znaków , dla UTF8mb4, który wykorzystuje 4 bajty na znak, wynosi 767/4 = 191 znaków.
Istnieją dwa rozwiązania tego problemu, jeśli chcesz użyć dłuższej kolumny niż limit:
W moim przypadku musiałem dodać Unikalny indeks do kolumny zawierającej ciąg SEO artykułu, ponieważ używam tylko
[A-z0-9\-]
znaków dla SEO, użyłem,latin1_general_ci
który używa tylko jednego bajtu na znak i dlatego kolumna może mieć 767 bajtów długości.drugiej Inną opcją dla mnie było utworzenie kolejnej kolumny, która przechowałaby skrót SEO, ta kolumna miałaby
UNIQUE
klucz do zapewnienia unikalności wartości SEO. Dodałbym równieżKEY
indeks do oryginalnej kolumny SEO, aby przyspieszyć wyszukiwanie.źródło
Odpowiedź na pytanie, dlaczego pojawia się komunikat o błędzie, została już udzielona przez wielu użytkowników tutaj. Moja odpowiedź dotyczy tego, jak to naprawić i jak używać.
Zobacz ten link .
use my_database_name;
set global innodb_large_prefix=on;
set global innodb_file_format=Barracuda;
Problem tej poprawki polega na tym, że eksportujesz bazę danych db na inny serwer (na przykład z hosta lokalnego na prawdziwy host) i nie możesz używać wiersza poleceń MySQL na tym serwerze. Nie możesz sprawić, żeby tam działało.
źródło
Otrzymałeś tę wiadomość, ponieważ 1 bajt jest równy 1 znakowi tylko wtedy, gdy używasz
latin-1
zestawu znaków. Jeśli użyjeszutf8
, każdy znak zostanie uznany za 3 bajty podczas definiowania kolumny klucza. Jeśli użyjeszutf8mb4
, każdy znak będzie traktowany jako 4 bajty podczas definiowania kolumny klucza. Dlatego musisz pomnożyć limit znaków pola klucza przez 1, 3 lub 4 (w moim przykładzie), aby określić liczbę bajtów, na którą pole klucza próbuje zezwolić. Jeśli używasz uft8mb4, możesz zdefiniować tylko 191 znaków dla natywnego pola klucza podstawowego InnoDB. Tylko nie przekraczaj 767 bajtów.źródło
możesz dodać kolumnę md5 długich kolumn
źródło
Wymień
utf8mb4
sięutf8
w pliku importu.źródło
Napotkaliśmy ten problem podczas próby dodania indeksu UNIQUE do pola VARCHAR (255) przy użyciu utf8mb4. Podczas gdy problem jest już dobrze zarysowany, chciałem dodać kilka praktycznych rad, w jaki sposób wymyśliliśmy to i rozwiązaliśmy.
Gdy używasz utf8mb4, znaki liczą się jako 4 bajty, podczas gdy w utf8 mogą one wynosić 3 bajty. Bazy danych InnoDB mają taki limit, że indeksy mogą zawierać tylko 767 bajtów. Tak więc, używając utf8, możesz przechowywać 255 znaków (767/3 = 255), ale używając utf8mb4, możesz przechowywać tylko 191 znaków (767/4 = 191).
Absolutnie możesz dodawać regularne indeksy dla
VARCHAR(255)
pól za pomocą utf8mb4, ale dzieje się tak, że rozmiar indeksu jest automatycznie obcinany do 191 znaków - jakunique_key
tutaj:Jest to w porządku, ponieważ zwykłe indeksy są po prostu używane, aby pomóc MySQL w szybszym wyszukiwaniu danych. Całe pole nie musi być indeksowane.
Dlaczego więc MySQL automatycznie obcina indeks dla zwykłych indeksów, ale zgłasza wyraźny błąd, próbując zrobić to dla unikalnych indeksów? Cóż, aby MySQL mógł dowiedzieć się, czy wstawiana lub aktualizowana wartość już istnieje, musi faktycznie zindeksować całą wartość, a nie tylko jej część.
Na koniec dnia, jeśli chcesz mieć unikalny indeks na polu, cała zawartość pola musi mieścić się w indeksie. W przypadku utf8mb4 oznacza to zmniejszenie długości pola VARCHAR do 191 znaków lub mniej. Jeśli nie potrzebujesz utf8mb4 dla tej tabeli lub pola, możesz upuścić go z powrotem do utf8 i mieć możliwość zachowania 255 pól długości.
źródło
Oto moja oryginalna odpowiedź:
Jednak nie działa we wszystkich przypadkach.
W rzeczywistości jest to problem z użyciem indeksów w kolumnach VARCHAR z zestawem znaków
utf8
(lubutf8mb4
), z kolumnami VARCHAR, które mają więcej niż pewną długość znaków. W przypadkuutf8mb4
tej pewnej długości wynosi 191.Więcej informacji na temat używania długich indeksów w bazie danych MySQL znajduje się w sekcji Długi indeks: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- zestaw znaków do utf8mb4
źródło
5 obejść:
Limit został podniesiony w 5.7.7 (MariaDB 10.2.2?). I można go zwiększyć za pomocą niektórych prac w 5.6 (10.1).
Jeśli osiągasz limit z powodu próby użycia ZESTAWU ZNAKÓW utf8mb4. Następnie wykonaj jedną z następujących czynności (każda ma wadę), aby uniknąć błędu:
- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes
źródło
Rozwiązałem ten problem z:
zastąpiony przez
wszystkie varchary, które mają więcej niż 200, zastępują je 191 lub ustawiają tekst.
źródło
Przeprowadziłem wyszukiwanie w tym temacie, ale w końcu wprowadziłem niestandardową zmianę
Dla środowiska roboczego MySQL 6.3.7 Dostępna jest graficzna międzyfazowa
W przypadku wersji poniżej 6.3.7 opcje bezpośrednie nie są dostępne, dlatego należy przejść do wiersza polecenia
źródło
set global innodb_default_row_format = DYNAMIC;
użyję, zobaczę ten komunikat: BŁĄD 1193 (HY000): Nieznana zmienna systemowa „innodb_default_row_format”Dla laravel 5.7 do 6.0
Kroki do naśladowania
App\Providers\AppServiceProvider.php
.use Illuminate\Support\Facades\Schema;
u góry.Schema::defaultStringLength(191);
to wszystko, ciesz się.
źródło
email
unikatowych elementów, ale należy przesłać wiadomość e-mail i uczynić ją wyjątkową. W przeciwieństwie do nieprzetworzonych danych łańcuchowych, skróty mają stałą szerokość i mogą być indeksowane i unikalne bez problemów. Zamiast zrozumieć problem, rozpowszechniasz okropne praktyki, których nie można skalować.zmień swoje zestawienie. Możesz użyć utf8_general_ci, który obsługuje prawie wszystkie
źródło
Właśnie przejście
utf8mb4
doutf8
tworzenia tabel rozwiązało mój problem. Na przykład:CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
doCREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
.źródło
Aby to naprawić, działa to dla mnie jak urok.
źródło
Opierając się na kolumnie podanej poniżej, te 2 kolumny ciągów zmiennych używają
utf8_general_ci
sortowania (utf8
sugerowany jest zestaw znaków).W MySQL,
utf8
charset używa maksymalnie 3 bajtów na każdy znak. Dlatego musiałby przydzielić 500 * 3 = 1500 bajtów, czyli znacznie więcej niż 767 bajtów, na które pozwala MySQL. Dlatego pojawia się ten błąd 1071.Innymi słowy, musisz obliczyć liczbę znaków na podstawie reprezentacji bajtów zestawu znaków, ponieważ nie każdy zestaw znaków jest reprezentacją pojedynczego bajtu (jak przypuszczałeś). IE
utf8
w MySQL używa maksymalnie 3 bajtów na znak, 767 / 3≈255 znaków, a dlautf8mb4
maksymalnie 4-bajtowej reprezentacji 767 / 4≈191 znaków.Wiadomo również, że MySQL
źródło
Znalazłem to zapytanie przydatne w wykrywaniu, które kolumny mają indeks naruszający maksymalną długość:
źródło
Sprawdź, czy
sql_mode
jest jakjeśli tak, zmień na
LUB
zrestartuj serwer zmieniając plik my.cnf (wstawiając następujące)
źródło
W moim przypadku miałem ten problem, kiedy tworzyłem kopię zapasową bazy danych przy użyciu znaków wyjściowych / wejściowych przekierowania linuxa. Dlatego zmieniam składnię, jak opisano poniżej. PS: za pomocą terminala Linux lub Mac.
Kopia zapasowa (bez przekierowania>)
Przywróć (bez <przekierowania)
Błąd „Określony klucz był zbyt długi; maksymalna długość klucza to 767 bajtów” po prostu zniknął.
źródło
Długości indeksu i MySQL / MariaDB
Laravel domyślnie używa zestawu znaków utf8mb4 , który obejmuje obsługę przechowywania „emoji” w bazie danych. Jeśli używasz wersji MySQL starszej niż wersja 5.7.7 lub MariaDB starszej niż wersja 10.2.2, może być konieczne ręczne skonfigurowanie domyślnej długości ciągu generowanego przez migracje, aby MySQL mógł utworzyć dla nich indeksy. Możesz to skonfigurować, wywołując metodę Schema :: defaultStringLength w swoim AppServiceProvider:
Alternatywnie możesz włączyć opcję innodb_large_prefix dla swojej bazy danych. Instrukcje dotyczące prawidłowego włączania tej opcji znajdują się w dokumentacji bazy danych.
Odnośnik z bloga: https://www.scratchcode.io/specified-key-too-long-error-in-laravel/
Odniesienie z oficjalnej dokumentacji laravel: https://laravel.com/docs/5.7/migrations
źródło
Jeśli tworzysz coś takiego:
powinno być coś takiego
ale musisz sprawdzić unikalność tej kolumny z kodu lub dodać nową kolumnę jako MD5 lub SHA1 kolumny varchar
źródło
Z powodu ograniczeń prefiksów ten błąd wystąpi. 767 bajtów to podane ograniczenie prefiksu dla tabel InnoDB w wersjach MySQL starszych niż 5.7. Dla tabel MyISAM ma 1000 bajtów. W MySQL w wersji 5.7 i wyższych limit ten został zwiększony do 3072 bajtów.
Uruchomienie poniższej usługi w usłudze powodującej błąd powinno rozwiązać problem. To musi być uruchomione w CLI MYSQL.
źródło
Zmień CHARSET pola indeksu reklamacji na „latin1”,
tj. ALTER TABELA tbl ZMIEŃ myfield myfield varchar (600) ZNAK ZESTAWU latin1 DEFAULT NULL;
latin1 zajmuje jeden bajt na jeden znak zamiast czterech
źródło
Jeśli zmieniłeś się
innodb_log_file_size
ostatnio, spróbuj przywrócić poprzednią wartość, która działała.źródło