Jeśli chcesz utf8[mb4]_unicode_ci, to może jak utf8[mb4]_unicode_520_cijeszcze bardziej.
Rick James
8
Nie wiem, jak się z tym czuję - zamiast naprawiać ich implementację, aby była zgodna z najnowszym standardem Unicode, zachowują przestarzałą wersję jako domyślną i ludzie muszą dodać „520”, aby użyć teraz właściwej. I nie jest kompatybilny z poprzednimi i starszymi wersjami, ponieważ nie można używać wersji „520” na starszych wersjach MySQL. Dlaczego nie mogli właśnie zaktualizować swojego istniejącego zestawu? To samo z „mb4”, naprawdę. Jaki kod naprawdę zależał od starego, ograniczonego / przestarzałego zachowania, aby uzasadnić zachowanie go jako domyślnego?
thomasrutter
7
Jeszcze lepsza jest domyślna wersja 8.0 utf8mb4_0900_ai_ci.
Rick James
Odpowiedzi:
1591
Te dwa zestawienia dotyczą kodowania znaków UTF-8. Różnice polegają na sposobie sortowania i porównywania tekstu.
Uwaga: W MySQL musisz utf8mb4raczej używać niż utf8. Myląco utf8jest wadliwą implementacją UTF-8 z wczesnych wersji MySQL, która pozostaje tylko dla kompatybilności wstecznej. Naprawiona wersja otrzymała nazwę utf8mb4.
Uwaga: Nowsze wersje MySQL mają zaktualizowane reguły sortowania Unicode, dostępne pod nazwami, na przykład utf8mb4_0900_ai_cidla równoważnych reguł opartych na Unicode 9.0 - i bez równoważnego _generalwariantu. Osoby czytające to teraz powinny prawdopodobnie użyć jednego z tych nowszych zestawień zamiast jednego _unicodelub_general . Wiele z tego, co napisano poniżej, nie jest już tak interesujące, jeśli zamiast tego możesz użyć jednego z nowszych zestawień.
Kluczowe różnice
utf8mb4_unicode_ci opiera się na oficjalnych regułach Unicode dotyczących uniwersalnego sortowania i porównywania, które dokładnie sortują w szerokim zakresie języków.
utf8mb4_general_cito uproszczony zestaw reguł sortowania, który ma na celu jak najlepiej wykonać, przy jednoczesnym zastosowaniu wielu skrótów mających na celu poprawę prędkości. Nie jest zgodny z zasadami Unicode i spowoduje niepożądane sortowanie lub porównanie w niektórych sytuacjach, na przykład podczas używania określonych języków lub znaków.
Na nowoczesnych serwerach ten wzrost wydajności będzie prawie znikomy. Został on opracowany w czasach, gdy serwery miały niewielki ułamek wydajności procesora dzisiejszych komputerów.
Korzyści z utf8mb4_unicode_ciponadutf8mb4_general_ci
utf8mb4_unicode_ci, który korzysta z reguł Unicode do sortowania i porównywania, stosuje dość złożony algorytm do poprawnego sortowania w szerokim zakresie języków i przy użyciu szerokiej gamy znaków specjalnych. Zasady te muszą uwzględniać konwencje specyficzne dla języka; nie wszyscy sortują swoje postacie w tak zwanym „porządku alfabetycznym”.
Jeśli chodzi o języki łacińskie (tj. „Europejskie”), nie ma dużej różnicy między sortowaniem Unicode a uproszczonym utf8mb4_general_cisortowaniem w MySQL, ale wciąż istnieje kilka różnic:
Na przykład sortowanie w Unicode sortuje „ß” jak „ss”, a „Œ” jak „OE” tak, jak ludzie używający tych znaków normalnie by tego chcieli, a utf8mb4_general_cisortuje je jako pojedyncze znaki (przypuszczalnie odpowiednio „s” i „e”) .
Niektóre znaki Unicode są zdefiniowane jako ignorowalne, co oznacza, że nie powinny się liczyć w kolejności sortowania, a porównanie powinno przejść do następnego znaku. utf8mb4_unicode_ciradzi sobie z nimi poprawnie.
W językach innych niż łacińskie, takich jak języki azjatyckie lub języki z różnymi alfabetami, może występować znacznie więcej różnic między sortowaniem w Unicode a utf8mb4_general_cisortowaniem uproszczonym . Przydatność utf8mb4_general_cizależy w dużej mierze od użytego języka. W przypadku niektórych języków będzie to dość nieodpowiednie.
Czego powinieneś użyć?
Niemal na pewno nie ma już powodu, aby z niego korzystać utf8mb4_general_ci, ponieważ pozostawiliśmy za sobą punkt, w którym szybkość procesora jest na tyle niska, że różnica w wydajności byłaby ważna. Twoja baza danych prawie na pewno będzie ograniczona innymi wąskimi gardłami.
W przeszłości niektóre osoby zalecały stosowanie, utf8mb4_general_ciz wyjątkiem przypadków, gdy dokładne sortowanie miało być na tyle ważne, aby uzasadnić koszt wydajności. Dzisiaj ten koszt wydajności prawie zniknął, a programiści poważniej podchodzą do internacjonalizacji.
Trzeba wysunąć argument, że jeśli prędkość jest dla Ciebie ważniejsza niż dokładność, równie dobrze możesz w ogóle nie dokonywać sortowania. Usprawnienie algorytmu jest trywialne, jeśli nie jest potrzebny, aby był dokładny. Tak, utf8mb4_general_cijest to kompromis, który chyba nie potrzebne ze względów prędkości i prawdopodobnie również nie nadaje się ze względu na dokładność.
Dodam jeszcze jedną rzecz, że nawet jeśli wiesz, że aplikacja obsługuje tylko język angielski, może nadal wymagać rozpoznawania nazwisk osób, które często mogą zawierać znaki używane w innych językach, w których równie ważne jest prawidłowe sortowanie . Używanie reguł Unicode do wszystkiego pomaga dodać spokój, że bardzo inteligentni ludzie Unicode pracowali bardzo ciężko, aby sortowanie działało poprawnie.
Co oznaczają części
Po pierwsze, cisłuży do sortowania i porównywania bez rozróżniania wielkości liter . Oznacza to, że nadaje się do danych tekstowych, a wielkość liter nie ma znaczenia. Inne typy zestawiania są cs(z rozróżnianiem wielkości liter) dla danych tekstowych bin, w których wielkość liter jest ważna, i tam , gdzie kodowanie musi się zgadzać, bit po bicie, co jest odpowiednie dla pól, które są naprawdę zakodowanymi danymi binarnymi (w tym na przykład Base64). Sortowanie z rozróżnianiem wielkości liter prowadzi do dziwnych wyników, a porównywanie z rozróżnianiem wielkości liter może powodować, że zduplikowane wartości różnią się tylko wielkością liter, więc sortowanie z rozróżnianiem wielkości liter nie jest korzystne dla danych tekstowych - jeśli wielkość liter jest dla Ciebie ważna, to w przeciwnym razie ignorowana interpunkcja i tak dalej jest prawdopodobnie również znaczący, a sortowanie binarne może być bardziej odpowiednie.
Dalej unicodelub generalodnosi się do konkretnych zasad sortowania i porównywania - w szczególności sposobu normalizacji lub porównania tekstu. Istnieje wiele różnych zestawów reguł dla kodowania znaków utf8mb4, ze unicodei generalbędąc dwa, że próba pracy dobrze we wszystkich możliwych językach niż jeden specyficzny. Różnice między tymi dwoma zestawami reguł są przedmiotem tej odpowiedzi. Zauważ, że unicodeużywa reguł z Unicode 4.0. Najnowsze wersje MySQL dodają zestawy reguł unicode_520przy użyciu reguł z Unicode 5.2 i 0900(upuszczając część „Unicode_”) przy użyciu reguł z Unicode 9.0.
I na koniec, utf8mb4oczywiście kodowanie znaków jest używane wewnętrznie. W tej odpowiedzi mówię tylko o kodowaniu opartym na Unicode.
@KahWeeTeng Należy nigdy, nigdy używać utf8_general_ci: to po prostu nie działa. To powrót do starych, złych dni głupoty ASCII sprzed pięćdziesięciu lat. Dopasowywanie bez rozróżniania wielkości liter w Unicode nie może być wykonane bez mapy folderów z UCD. Na przykład „Σίσυφος” zawiera trzy różne sigmy; lub jak małymi literami „TSCHüẞ” jest „tschüβ”, ale wielką literą „tschüβ” jest „TSCHÜSS”. Możesz mieć rację lub możesz być szybki. Dlatego musisz go użyć utf8_unicode_ci, ponieważ jeśli nie zależy ci na poprawności, to sprawienie, by było nieskończenie szybkie, jest banalne.
tchrist
7
Po przeczytaniu tego odkryłem również, że utf8_unicode_ci weźmie pod uwagę wszystkie znaki o tej samej wadze sortowania jako równe dla celów porównania równości. Prowadzi to do przypadków, w których "か" == "が"lub "ǽ" == "æ". Sortowanie to ma sens, ale może być zaskakujące, gdy wybierasz
Mat Schaffer
4
@DanHorvat Jedynym praktycznym powodem, aby ograniczyć się do starszego, bardziej ograniczonego podzbioru MySQL, jest posiadanie starej wersji MySQL, która nie obsługuje bardziej kompletnego utf8mb4. 5.5.3 ma ponad 5 lat. Doceniam, że Plesk działa na innym harmonogramem MySQL, ale większość dystrybucje są na MySQL 5.5 i teraz Plesk 11.x robi obsługą MySQL 5.5 po aktualizacji jego składników.
thomasrutter,
22
Nie zgodziłbym się z tym, że używanie nowszego, bardziej zgodnego ze standardami wariantu, jest złą praktyką i myślę, że nałogowe jest nazywanie ludzi złymi programistami w związku z czymś takim. Warto również zauważyć, że moja obecna odpowiedź brzmi: „ w nowych wersjach MySQL używaj utf8mb4 zamiast utf8”, moje podkreślenie.
thomasrutter,
23
@ DanHorvat utf8mb4jest jedynym poprawnym wyborem . Gdy utf8utkniesz w jakimś MySQL, 3-bajtowym wariancie UTF8, który tylko MySQL (i MariaDB) wiedzą, co zrobić. Reszta świata używa UTF8, który może zawierać do 4 bajtów na znak . MySQL devs źle nazwali swoje kodowanie homebrew utf8i aby nie złamać kompatybilności wstecznej, muszą teraz odnosić się do prawdziwego UTF8 jako utf8mb4.
Stijn de Witt
162
Chciałem wiedzieć, jaka jest różnica w wydajności między używaniem utf8_general_cii utf8_unicode_ci, ale nie znalazłem żadnych testów porównawczych w Internecie, więc postanowiłem sam je stworzyć.
Stworzyłem bardzo prostą tabelę z 500 000 wierszy:
CREATETABLE test(
ID INT(11)DEFAULTNULL,
Description VARCHAR(20)DEFAULTNULL)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
Następnie wypełniłem je losowymi danymi, uruchamiając tę procedurę składowaną:
CREATEPROCEDURE randomizer()BEGINDECLARE i INT DEFAULT0;DECLARE random CHAR(20);
theloop: loop
SET random = CONV(FLOOR(RAND()*99999999999999),20,36);INSERTINTO test VALUES(i+1, random);SET i=i+1;IF i =500000THEN
LEAVE theloop;ENDIF;END LOOP theloop;END
Następnie utworzyłem następujące procedury składowane, aby przeprowadzić proste testy porównawcze SELECT, SELECTz LIKEi sortowanie ( SELECTz ORDER BY):
CREATEPROCEDURE benchmark_simple_select()BEGINDECLARE i INT DEFAULT0;
theloop: loop
SELECT*FROM test
WHERE Description ='test'COLLATE utf8_general_ci;SET i = i +1;IF i =30THEN
LEAVE theloop;ENDIF;END LOOP theloop;END;CREATEPROCEDURE benchmark_select_like()BEGINDECLARE i INT DEFAULT0;
theloop: loop
SELECT*FROM test
WHERE Description LIKE'%test'COLLATE utf8_general_ci;SET i = i +1;IF i =30THEN
LEAVE theloop;ENDIF;END LOOP theloop;END;CREATEPROCEDURE benchmark_order_by()BEGINDECLARE i INT DEFAULT0;
theloop: loop
SELECT*FROM test
WHERE ID > FLOOR(1+ RAND()*(400000-1))ORDERBY Description COLLATE utf8_general_ci LIMIT 1000;SET i = i +1;IF i =10THEN
LEAVE theloop;ENDIF;END LOOP theloop;END;
W procedurach przechowywanych stosuje się powyższe utf8_general_cizestawienie, ale oczywiście podczas testów użyłem zarówno utf8_general_cii utf8_unicode_ci.
Każdą procedurę przechowywaną wywołałem 5 razy dla każdego zestawienia (5 razy dla utf8_general_cii 5 razy dla utf8_unicode_ci), a następnie obliczyłem wartości średnie.
Moje wyniki to:
benchmark_simple_select()
z utf8_general_ci: 9,957 ms
z utf8_unicode_ci: 10 271 ms
W tym teście używanie utf8_unicode_cijest wolniejsze niż utf8_general_cio 3,2%.
benchmark_select_like()
z utf8_general_ci: 11441 ms
z utf8_unicode_ci: 12,811 ms
W tym teście używanie utf8_unicode_cijest wolniejsze niż utf8_general_cio 12%.
benchmark_order_by()
z utf8_general_ci: 11944 ms
z utf8_unicode_ci: 12887 ms
W tym teście używanie utf8_unicode_cijest wolniejsze niż utf8_general_cio 7,9%.
Niezły test, dziękuję za udostępnienie. Otrzymuję rozsądnie podobne liczby (MySQL v5.6.12 w systemie Windows): 10%, 4%, 8%. Zgadzam się: wzrost wydajności utf8_general_cijest po prostu zbyt minimalny, aby być wartym użycia.
RandomSeed
10
1) Ale czy ten test porównawczy nie powinien generować podobnych wyników dla dwóch zestawień z definicji? To znaczy CONV(FLOOR(RAND() * 99999999999999), 20, 36)generuje tylko ASCII i nie ma znaków Unicode do przetworzenia przez algorytmy sortowania. 2) Description = 'test' COLLATE ...i Description LIKE 'test%' COLLATE ...przetwarzają tylko jeden ciąg („test”) w czasie wykonywania, prawda? 3) W rzeczywistych aplikacjach kolumny używane do porządkowania prawdopodobnie zostałyby zaindeksowane, a szybkość indeksowania dla różnych zestawień z prawdziwym tekstem innym niż ASCII może się różnić.
Halil Özgür
2
@ HalilÖzgür - twój punkt jest częściowo błędny. Wydaje mi się, że nie chodzi o to, aby wartość punktu kodowego znajdowała się poza ASCII (co general_ci poradziłaby sobie poprawnie), ale o specyficzne cechy, takie jak traktowanie umlautów napisanych jako „Uml ea ute” lub niektórych takich subtelności.
W skrócie: utf8_unicode_ci używa algorytmu sortowania Unicode zdefiniowanego w standardach Unicode, podczas gdy utf8_general_ci jest prostszym porządkiem sortowania, co powoduje „mniej dokładne” wyniki sortowania.
dzięki. takie było moje wrażenie. wezmę hit wydajności :)
onassar
7
Jeśli nie zależy ci na poprawności, nie jest konieczne, aby każdy algorytm był nieskończenie szybki. Po prostu użyj utf8_unicode_cii udawaj, że ten drugi nie istnieje.
tchrist
1
@ tchrist, ale jeśli zależy ci na pewnej równowadze między poprawnością a szybkością, utf8_general_cimoże być dla ciebie
Shelvacu
@tchrist Nigdy nie zostań programistą gier;)
Stijn de Witt
1
@onassar - MySQL 8.0 twierdzi, że znacznie poprawił wydajność wszystkich zestawień.
W przypadku dowolnego zestawu znaków Unicode operacje wykonywane przy użyciu sortowania _general_ci są szybsze niż w przypadku sortowania _unicode_ci. Na przykład porównania dla zestawienia utf8_general_ci są szybsze, ale nieco mniej poprawne, niż porównania dla utf8_unicode_ci. Powodem tego jest to, że utf8_unicode_ci obsługuje mapowania, takie jak rozszerzenia; to znaczy, gdy jeden znak porównuje się jako równy kombinacjom innych znaków. Na przykład w języku niemieckim i niektórych innych językach „ß” jest równe „ss”. utf8_unicode_ci obsługuje również skurcze i znaki ignorowalne. utf8_general_ci to starsze zestawienie, które nie obsługuje rozszerzeń, skurczów ani ignorowalnych znaków. Może dokonywać tylko porównań między postaciami.
Podsumowując, utf_general_ci używa mniejszego i mniej poprawnego (zgodnie ze standardem) zestawu porównań niż utf_unicode_ci, który powinien implementować cały standard. Zestaw general_ci będzie szybszy, ponieważ jest mniej obliczeń do zrobienia.
Nie ma czegoś takiego jak „nieco mniej poprawne”. Prawidłowość jest cechą logiczną; nie dopuszcza modyfikatorów stopnia. Po prostu użyj utf8_unicode_cii udawaj, że uszkodzona wersja z błędami nie istnieje.
tchrist
2
Miałem problemy z uzyskaniem 5.6.15 ustawienia collation_connection i okazuje się, że musisz przekazać go w linii SET, np. „SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci”. Podziękowania dla Mathiasa Bynensa za rozwiązanie, oto jego bardzo przydatny przewodnik: mathiasbynens.be/notes/mysql-utf8mb4
Steve Hibbert
4
@tchrist Problem z mówieniem o poprawności jest logiczny, ponieważ nie uwzględnia sytuacji, które nie polegają na absolutnej poprawności. Twój punkt bazowy nie jest nieważny, ani nie próbuję popierać korzyści wynikających z general_ci, ale twoje ogólne stwierdzenie o poprawności można łatwo obalić. Robię to codziennie w moim zawodzie. Pomijając komedię, Stuart ma tutaj rację .
Anthony
5
Dzięki geolokalizacji lub tworzeniu gier cały czas wymieniamy poprawność z wydajnością. I oczywiście poprawność to rzeczywista liczba między, 0a 1nie bool. :) EG wybranie punktów geograficznych w obwiedni jest przybliżeniem „punktów w pobliżu”, co nie jest tak dobre, jak obliczenie odległości między punktem a punktem odniesienia i filtrowanie tego. Ale oba są przybliżeniem i w rzeczywistości pełna poprawność jest w większości nieosiągalna. Zobacz paradoks wybrzeża i IEEE 754
Stijn de Witt
4
TL; DR : Proszę podać program, który drukuje poprawny wynik dla1/3
Stijn de Witt
7
Krótko mówiąc:
Jeśli potrzebujesz lepszego porządku sortowania - użyj utf8_unicode_ci(jest to preferowana metoda),
ale jeśli jesteś całkowicie zainteresowany wydajnością - użyj utf8_general_ci, ale wiedz, że jest trochę przestarzała.
Różnice pod względem wydajności są bardzo niewielkie.
Oba są już nieaktualne - więcej informacji znajduje się w zaakceptowanej odpowiedzi
thomasrutter
OK, dziękuję @ thomasrutter
simhumileco
6
Niektóre szczegóły (PL)
Jak możemy przeczytać tutaj ( Peter Gulutzan ), istnieje różnica w sortowaniu / porównywaniu polskiej litery „Ł” (L z pociągnięciem - html esc:) Ł(małe litery: „ł” - html esc:) ł- przyjmujemy następujące założenie:
utf8_polish_ci Ł greater than L and less than M
utf8_unicode_ci Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci Ł greater than Z
W języku polskim litera Łjest po literze Li przed nią M. Żadne z tych kodów nie jest lepsze ani gorsze - zależy to od twoich potrzeb.
Istnieją dwie duże różnice w sortowaniu i dopasowywaniu znaków:
Sortowanie :
utf8mb4_general_ci usuwa wszystkie akcenty i sortuje jeden po drugim, co może powodować niepoprawne wyniki sortowania.
utf8mb4_unicode_ci sortuje dokładne.
Dopasowanie postaci
Pasują do znaków inaczej.
Na przykład w utf8mb4_unicode_citobie masz i != ı, ale w utf8mb4_general_cinim się trzyma ı=i.
Wyobraź sobie na przykład, że masz wiersz name="Yılmaz". Następnie
select id from users where name='Yilmaz';
zwróci wiersz, jeśli kolokacja jest utf8mb4_general_ci, ale jeśli zostanie skolokowany utf8mb4_unicode_ci, nie zwróci wiersza!
Z drugiej strony mamy, że a=ªi ß=ssw utf8mb4_unicode_ciktórej nie jest w przypadku utf8mb4_general_ci. Więc wyobraź sobie, że masz wiersz z name="ªßi", a następnie
select id from users where name='assi';
zwróci wiersz, jeśli kolokacja jest utf8mb4_unicode_ci, ale nie zwróci wiersza, jeśli kolokacja jest ustawiona na utf8mb4_general_ci.
Pełna lista dopasowań dla każdej kolokacji znajduje się tutaj .
utf8[mb4]_unicode_ci
, to może jakutf8[mb4]_unicode_520_ci
jeszcze bardziej.utf8mb4_0900_ai_ci
.Odpowiedzi:
Te dwa zestawienia dotyczą kodowania znaków UTF-8. Różnice polegają na sposobie sortowania i porównywania tekstu.
Uwaga: W MySQL musisz
utf8mb4
raczej używać niżutf8
. Mylącoutf8
jest wadliwą implementacją UTF-8 z wczesnych wersji MySQL, która pozostaje tylko dla kompatybilności wstecznej. Naprawiona wersja otrzymała nazwęutf8mb4
.Uwaga: Nowsze wersje MySQL mają zaktualizowane reguły sortowania Unicode, dostępne pod nazwami, na przykład
utf8mb4_0900_ai_ci
dla równoważnych reguł opartych na Unicode 9.0 - i bez równoważnego_general
wariantu. Osoby czytające to teraz powinny prawdopodobnie użyć jednego z tych nowszych zestawień zamiast jednego_unicode
lub_general
. Wiele z tego, co napisano poniżej, nie jest już tak interesujące, jeśli zamiast tego możesz użyć jednego z nowszych zestawień.Kluczowe różnice
utf8mb4_unicode_ci
opiera się na oficjalnych regułach Unicode dotyczących uniwersalnego sortowania i porównywania, które dokładnie sortują w szerokim zakresie języków.utf8mb4_general_ci
to uproszczony zestaw reguł sortowania, który ma na celu jak najlepiej wykonać, przy jednoczesnym zastosowaniu wielu skrótów mających na celu poprawę prędkości. Nie jest zgodny z zasadami Unicode i spowoduje niepożądane sortowanie lub porównanie w niektórych sytuacjach, na przykład podczas używania określonych języków lub znaków.Na nowoczesnych serwerach ten wzrost wydajności będzie prawie znikomy. Został on opracowany w czasach, gdy serwery miały niewielki ułamek wydajności procesora dzisiejszych komputerów.
Korzyści z
utf8mb4_unicode_ci
ponadutf8mb4_general_ci
utf8mb4_unicode_ci
, który korzysta z reguł Unicode do sortowania i porównywania, stosuje dość złożony algorytm do poprawnego sortowania w szerokim zakresie języków i przy użyciu szerokiej gamy znaków specjalnych. Zasady te muszą uwzględniać konwencje specyficzne dla języka; nie wszyscy sortują swoje postacie w tak zwanym „porządku alfabetycznym”.Jeśli chodzi o języki łacińskie (tj. „Europejskie”), nie ma dużej różnicy między sortowaniem Unicode a uproszczonym
utf8mb4_general_ci
sortowaniem w MySQL, ale wciąż istnieje kilka różnic:Na przykład sortowanie w Unicode sortuje „ß” jak „ss”, a „Œ” jak „OE” tak, jak ludzie używający tych znaków normalnie by tego chcieli, a
utf8mb4_general_ci
sortuje je jako pojedyncze znaki (przypuszczalnie odpowiednio „s” i „e”) .Niektóre znaki Unicode są zdefiniowane jako ignorowalne, co oznacza, że nie powinny się liczyć w kolejności sortowania, a porównanie powinno przejść do następnego znaku.
utf8mb4_unicode_ci
radzi sobie z nimi poprawnie.W językach innych niż łacińskie, takich jak języki azjatyckie lub języki z różnymi alfabetami, może występować znacznie więcej różnic między sortowaniem w Unicode a
utf8mb4_general_ci
sortowaniem uproszczonym . Przydatnośćutf8mb4_general_ci
zależy w dużej mierze od użytego języka. W przypadku niektórych języków będzie to dość nieodpowiednie.Czego powinieneś użyć?
Niemal na pewno nie ma już powodu, aby z niego korzystać
utf8mb4_general_ci
, ponieważ pozostawiliśmy za sobą punkt, w którym szybkość procesora jest na tyle niska, że różnica w wydajności byłaby ważna. Twoja baza danych prawie na pewno będzie ograniczona innymi wąskimi gardłami.W przeszłości niektóre osoby zalecały stosowanie,
utf8mb4_general_ci
z wyjątkiem przypadków, gdy dokładne sortowanie miało być na tyle ważne, aby uzasadnić koszt wydajności. Dzisiaj ten koszt wydajności prawie zniknął, a programiści poważniej podchodzą do internacjonalizacji.Trzeba wysunąć argument, że jeśli prędkość jest dla Ciebie ważniejsza niż dokładność, równie dobrze możesz w ogóle nie dokonywać sortowania. Usprawnienie algorytmu jest trywialne, jeśli nie jest potrzebny, aby był dokładny. Tak,
utf8mb4_general_ci
jest to kompromis, który chyba nie potrzebne ze względów prędkości i prawdopodobnie również nie nadaje się ze względu na dokładność.Dodam jeszcze jedną rzecz, że nawet jeśli wiesz, że aplikacja obsługuje tylko język angielski, może nadal wymagać rozpoznawania nazwisk osób, które często mogą zawierać znaki używane w innych językach, w których równie ważne jest prawidłowe sortowanie . Używanie reguł Unicode do wszystkiego pomaga dodać spokój, że bardzo inteligentni ludzie Unicode pracowali bardzo ciężko, aby sortowanie działało poprawnie.
Co oznaczają części
Po pierwsze,
ci
służy do sortowania i porównywania bez rozróżniania wielkości liter . Oznacza to, że nadaje się do danych tekstowych, a wielkość liter nie ma znaczenia. Inne typy zestawiania sącs
(z rozróżnianiem wielkości liter) dla danych tekstowychbin
, w których wielkość liter jest ważna, i tam , gdzie kodowanie musi się zgadzać, bit po bicie, co jest odpowiednie dla pól, które są naprawdę zakodowanymi danymi binarnymi (w tym na przykład Base64). Sortowanie z rozróżnianiem wielkości liter prowadzi do dziwnych wyników, a porównywanie z rozróżnianiem wielkości liter może powodować, że zduplikowane wartości różnią się tylko wielkością liter, więc sortowanie z rozróżnianiem wielkości liter nie jest korzystne dla danych tekstowych - jeśli wielkość liter jest dla Ciebie ważna, to w przeciwnym razie ignorowana interpunkcja i tak dalej jest prawdopodobnie również znaczący, a sortowanie binarne może być bardziej odpowiednie.Dalej
unicode
lubgeneral
odnosi się do konkretnych zasad sortowania i porównywania - w szczególności sposobu normalizacji lub porównania tekstu. Istnieje wiele różnych zestawów reguł dla kodowania znaków utf8mb4, zeunicode
igeneral
będąc dwa, że próba pracy dobrze we wszystkich możliwych językach niż jeden specyficzny. Różnice między tymi dwoma zestawami reguł są przedmiotem tej odpowiedzi. Zauważ, żeunicode
używa reguł z Unicode 4.0. Najnowsze wersje MySQL dodają zestawy regułunicode_520
przy użyciu reguł z Unicode 5.2 i0900
(upuszczając część „Unicode_”) przy użyciu reguł z Unicode 9.0.I na koniec,
utf8mb4
oczywiście kodowanie znaków jest używane wewnętrznie. W tej odpowiedzi mówię tylko o kodowaniu opartym na Unicode.źródło
utf8_general_ci
: to po prostu nie działa. To powrót do starych, złych dni głupoty ASCII sprzed pięćdziesięciu lat. Dopasowywanie bez rozróżniania wielkości liter w Unicode nie może być wykonane bez mapy folderów z UCD. Na przykład „Σίσυφος” zawiera trzy różne sigmy; lub jak małymi literami „TSCHüẞ” jest „tschüβ”, ale wielką literą „tschüβ” jest „TSCHÜSS”. Możesz mieć rację lub możesz być szybki. Dlatego musisz go użyćutf8_unicode_ci
, ponieważ jeśli nie zależy ci na poprawności, to sprawienie, by było nieskończenie szybkie, jest banalne."か" == "が"
lub"ǽ" == "æ"
. Sortowanie to ma sens, ale może być zaskakujące, gdy wybieraszutf8mb4
jest jedynym poprawnym wyborem . Gdyutf8
utkniesz w jakimś MySQL, 3-bajtowym wariancie UTF8, który tylko MySQL (i MariaDB) wiedzą, co zrobić. Reszta świata używa UTF8, który może zawierać do 4 bajtów na znak . MySQL devs źle nazwali swoje kodowanie homebrewutf8
i aby nie złamać kompatybilności wstecznej, muszą teraz odnosić się do prawdziwego UTF8 jakoutf8mb4
.Chciałem wiedzieć, jaka jest różnica w wydajności między używaniem
utf8_general_ci
iutf8_unicode_ci
, ale nie znalazłem żadnych testów porównawczych w Internecie, więc postanowiłem sam je stworzyć.Stworzyłem bardzo prostą tabelę z 500 000 wierszy:
Następnie wypełniłem je losowymi danymi, uruchamiając tę procedurę składowaną:
Następnie utworzyłem następujące procedury składowane, aby przeprowadzić proste testy porównawcze
SELECT
,SELECT
zLIKE
i sortowanie (SELECT
zORDER BY
):W procedurach przechowywanych stosuje się powyższe
utf8_general_ci
zestawienie, ale oczywiście podczas testów użyłem zarównoutf8_general_ci
iutf8_unicode_ci
.Każdą procedurę przechowywaną wywołałem 5 razy dla każdego zestawienia (5 razy dla
utf8_general_ci
i 5 razy dlautf8_unicode_ci
), a następnie obliczyłem wartości średnie.Moje wyniki to:
benchmark_simple_select()
utf8_general_ci
: 9,957 msutf8_unicode_ci
: 10 271 msW tym teście używanie
utf8_unicode_ci
jest wolniejsze niżutf8_general_ci
o 3,2%.benchmark_select_like()
utf8_general_ci
: 11441 msutf8_unicode_ci
: 12,811 msW tym teście używanie
utf8_unicode_ci
jest wolniejsze niżutf8_general_ci
o 12%.benchmark_order_by()
utf8_general_ci
: 11944 msutf8_unicode_ci
: 12887 msW tym teście używanie
utf8_unicode_ci
jest wolniejsze niżutf8_general_ci
o 7,9%.źródło
utf8_general_ci
jest po prostu zbyt minimalny, aby być wartym użycia.CONV(FLOOR(RAND() * 99999999999999), 20, 36)
generuje tylko ASCII i nie ma znaków Unicode do przetworzenia przez algorytmy sortowania. 2)Description = 'test' COLLATE ...
iDescription LIKE 'test%' COLLATE ...
przetwarzają tylko jeden ciąg („test”) w czasie wykonywania, prawda? 3) W rzeczywistych aplikacjach kolumny używane do porządkowania prawdopodobnie zostałyby zaindeksowane, a szybkość indeksowania dla różnych zestawień z prawdziwym tekstem innym niż ASCII może się różnić.Ten post opisuje to bardzo ładnie.
W skrócie: utf8_unicode_ci używa algorytmu sortowania Unicode zdefiniowanego w standardach Unicode, podczas gdy utf8_general_ci jest prostszym porządkiem sortowania, co powoduje „mniej dokładne” wyniki sortowania.
źródło
utf8_unicode_ci
i udawaj, że ten drugi nie istnieje.utf8_general_ci
może być dla ciebieZobacz instrukcję mysql, sekcja Zestawy znaków Unicode :
Podsumowując, utf_general_ci używa mniejszego i mniej poprawnego (zgodnie ze standardem) zestawu porównań niż utf_unicode_ci, który powinien implementować cały standard. Zestaw general_ci będzie szybszy, ponieważ jest mniej obliczeń do zrobienia.
źródło
utf8_unicode_ci
i udawaj, że uszkodzona wersja z błędami nie istnieje.0
a1
nie bool. :) EG wybranie punktów geograficznych w obwiedni jest przybliżeniem „punktów w pobliżu”, co nie jest tak dobre, jak obliczenie odległości między punktem a punktem odniesienia i filtrowanie tego. Ale oba są przybliżeniem i w rzeczywistości pełna poprawność jest w większości nieosiągalna. Zobacz paradoks wybrzeża i IEEE 7541/3
Krótko mówiąc:
Jeśli potrzebujesz lepszego porządku sortowania - użyj
utf8_unicode_ci
(jest to preferowana metoda),ale jeśli jesteś całkowicie zainteresowany wydajnością - użyj
utf8_general_ci
, ale wiedz, że jest trochę przestarzała.Różnice pod względem wydajności są bardzo niewielkie.
źródło
Niektóre szczegóły (PL)
Jak możemy przeczytać tutaj ( Peter Gulutzan ), istnieje różnica w sortowaniu / porównywaniu polskiej litery „Ł” (L z pociągnięciem - html esc:)
Ł
(małe litery: „ł” - html esc:)ł
- przyjmujemy następujące założenie:W języku polskim litera
Ł
jest po literzeL
i przed niąM
. Żadne z tych kodów nie jest lepsze ani gorsze - zależy to od twoich potrzeb.źródło
Istnieją dwie duże różnice w sortowaniu i dopasowywaniu znaków:
Sortowanie :
utf8mb4_general_ci
usuwa wszystkie akcenty i sortuje jeden po drugim, co może powodować niepoprawne wyniki sortowania.utf8mb4_unicode_ci
sortuje dokładne.Dopasowanie postaci
Pasują do znaków inaczej.
Na przykład w
utf8mb4_unicode_ci
tobie maszi != ı
, ale wutf8mb4_general_ci
nim się trzymaı=i
.Wyobraź sobie na przykład, że masz wiersz
name="Yılmaz"
. Następniezwróci wiersz, jeśli kolokacja jest
utf8mb4_general_ci
, ale jeśli zostanie skolokowanyutf8mb4_unicode_ci
, nie zwróci wiersza!Z drugiej strony mamy, że
a=ª
iß=ss
wutf8mb4_unicode_ci
której nie jest w przypadkuutf8mb4_general_ci
. Więc wyobraź sobie, że masz wiersz zname="ªßi"
, a następniezwróci wiersz, jeśli kolokacja jest
utf8mb4_unicode_ci
, ale nie zwróci wiersza, jeśli kolokacja jest ustawiona nautf8mb4_general_ci
.Pełna lista dopasowań dla każdej kolokacji znajduje się tutaj .
źródło
Zgodnie z tym postem, MySQL 5.7 ma znacznie wyższą wydajność w porównaniu z utf8mb4_general_ci zamiast utf8mb4_unicode_ci: https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mysql-performance /
źródło