Wrzesień 2021 edit:Używam MySQL 8.0 od kilku lat, więc oto kilka zaktualizowanych informacji.
Podręcznik MySQL ma teraz bardzo pouczającą stronę dotyczące konwersji między utf8mb3
(obecnie znany również jako utf8
) i utf8mb4
. utf8mb3
jest przestarzały i zostanie usunięty
ostatecznie; a kiedy zostanie usunięty, jego aktualny alias, utf8
, będzie odnosić się do utf8mb4
zamiast tego.
Z przestarzałym utf8mb3
, możesz przechowywać do 255 znaków w indeksie, podczas gdy z utf8mb4
, do 191, przy użyciu COMPACT
lub REDUNDANT
format wiersza.
Z COMPRESSED
lub DYNAMIC
format wiersza, prefiksy klucza indeksu mogą mieć do 3072 bajtów. Dzięki nim możesz zaindeksować do 1024 znaków dla utf8mb3
i 768 znaków dla utf8mb4
.
Poniżej znajduje się moja poprzednia odpowiedź, która wyjaśnia część logiki stojącej za liczbą znaków możesz indeksować w stosunku do liczby bajtów .
Muszę zrewidować swoją odpowiedź ze względu na moje badania. Pierwotnie zamieściłem to (cytując siebie):
Wierzę, że odpowiedź brzmi, że nie możesz wiedzieć, ile znaków będzie w indeksie, ponieważ nie możesz wiedzieć, ile bajtów będą miały twoje znaki (chyba że zrobisz coś, aby wykluczyć znaki wielobajtowe).
I nie jestem pewien, ale może to i tak jest poprawne, ale nie do końca tak, jak myślałem.
Oto prawidłowa odpowiedź:
MySQL zakłada 3 bajty na znak utf8. 255 znaków to maksymalny rozmiar indeksu, jaki można określić na kolumnę, ponieważ 256x3=768, co przekracza limit 767 bajtów.
Jeśli nie określisz rozmiaru indeksu, MySQL wybierze maksymalny rozmiar (tj. 255 na kolumnę). Ograniczenia UNIQUE nie można umieścić na kolumnie utf8, której długość jest większa niż 255, ponieważ unikalny indeks musi zawierać całą wartość komórki. Ale można użyć zwykłego indeksu - po prostu zindeksuje pierwsze 255 znaków (lub pierwsze 767 bajtów?). I tu wciąż jest dla mnie jakaś tajemnica.
MySTERY:Widzę, dlaczego MySQL przyjmuje 3 bajty na znak, ze względów bezpieczeństwa, ponieważ w przeciwnym razie ograniczenie UNIQUE może zostać złamane. Ale dokumentacja wydaje się sugerować, że indeks w rzeczywistości ma rozmiar w bajtach, a nie w znakach. Załóżmy więc, że stawiasz 255 indeks char (765 bajtów) na varchar(256 ). Jeśli wszystkie znaki, które przechowujesz, są ASCII, 1-bajtowymi znakami, takimi jak A-Z, a-z, 0-9, wtedy możesz dopasować całą kolumnę do indeksu 767 bajtów. I wygląda na to, że tak właśnie by się stało.
Poniżej znajduje się więcej informacji z mojej oryginalnej odpowiedzi na temat znaków, bajtów itp.
Według wikipedii , znak UTF-8 może mieć długość 1,2, 3 lub 4 bajty.Ale zgodnie z ta dokumentacja mysql , maksymalny rozmiar znaku to 3 bajty, a więc każdy indeks indeksu kolumny powyżej 255 znaków może osiągnąć ten limit bajtów. Ale jak rozumiem, może nie. Jeśli większość twoich znaków jest w zakresie ASCII, twój średni rozmiar znaku będzie bliższy 1 bajtowi. Jeśli średni rozmiar znaku wynosi na przykład 1,3 bajta (głównie 1 bajt, ale znaczna liczba znaków 2-3 bajtowych), możesz podać indeks 767/1,3
Tak więc, jeśli przechowujesz głównie 1-bajtowe znaki, twój rzeczywisty limit znaków byłby bardziej podobny do:767 / 1,3 =590. Ale okazuje się, że tak nie działa. 255 znaków to limit.
Jak wspomniano w tej dokumentacji MySQL ,
Limity prefiksów są mierzone w bajtach, natomiast długość prefiksów w instrukcjach CREATE INDEX jest interpretowana jako liczba znaków dla niebinarnych typów danych (CHAR, VARCHAR, TEXT). Weź to pod uwagę podczas określania długości prefiksu dla kolumny, która używa zestawu znaków wielobajtowych.
Wygląda na to, że MySQL doradza ludziom wykonanie obliczeń/oszacowań, tak jak ja właśnie to zrobiłem, aby określić rozmiar klucza dla kolumny varchar. Ale w rzeczywistości nie możesz podaj indeks większy niż 255 dla kolumn utf8.
Wreszcie, jeśli ponownie odwołasz się do mojego drugiego linku, jest też to:
Gdy opcja konfiguracyjna innodb_large_prefix jest włączona, ten limit długości jest zwiększany do 3072 bajtów dla tabel InnoDB, które używają formatów wierszy DYNAMICZNYCH i KOMPRESOWANYCH.
Wygląda więc na to, że możesz uzyskać znacznie większe indeksy, jeśli chcesz, przy odrobinie poprawek. Tylko upewnij się, że formaty wierszy są DYNAMICZNE lub SKOMPRESOWANE. W takim przypadku prawdopodobnie możesz określić indeks o długości 1023 lub 1024 znaków.
Nawiasem mówiąc, okazuje się, że możesz przechowywać 4-bajtowe znaki za pomocą [zestawu znaków utf8mb4][4].Zestaw znaków utf8 najwyraźniej przechowuje tylko [znaki „płaszczyzny 0”][5].EDYCJA:
Właśnie próbowałem utworzyć indeks złożony na kolumnie varchar(511) z kolumną tinyint(1) i otrzymałem komunikat o błędzie informujący, że maksymalny rozmiar indeksu to 767 bajtów. To sprawia, że wierzę, że MySQL zakłada, że kolumny zestawu znaków utf8 będą zawierać 3 bajty na znak (maksymalnie) i pozwalają na użycie maksymalnie 255 znaków. Ale być może dotyczy to tylko indeksów złożonych. Zaktualizuję swoją odpowiedź, gdy dowiem się więcej. Ale na razie zostawiam to jako edycję.