Pomiędzy utf8_general_ci
i utf8_unicode_ci
czy są jakieś różnice pod względem wydajności?
utf8[mb4]_unicode_ci
, to może jak utf8[mb4]_unicode_520_ci
jeszcze bardziej.
utf8mb4_0900_ai_ci
.
Pomiędzy utf8_general_ci
i utf8_unicode_ci
czy są jakieś różnice pod względem wydajności?
utf8[mb4]_unicode_ci
, to może jak utf8[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ąco utf8
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 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 unicode
lub general
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, ze unicode
i general
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ż, że unicode
używa reguł z Unicode 4.0. Najnowsze wersje MySQL dodają zestawy reguł unicode_520
przy użyciu reguł z Unicode 5.2 i 0900
(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.
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 wybierasz
utf8mb4
jest jedynym poprawnym wyborem . Gdy utf8
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 homebrew utf8
i aby nie złamać kompatybilności wstecznej, muszą teraz odnosić się do prawdziwego UTF8 jako utf8mb4
.
Chciałem wiedzieć, jaka jest różnica w wydajności między używaniem utf8_general_ci
i 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:
CREATE TABLE test(
ID INT(11) DEFAULT NULL,
Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
Następnie wypełniłem je losowymi danymi, uruchamiając tę procedurę składowaną:
CREATE PROCEDURE randomizer()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE random CHAR(20) ;
theloop: loop
SET random = CONV(FLOOR(RAND() * 99999999999999), 20, 36);
INSERT INTO test VALUES (i+1, random);
SET i=i+1;
IF i = 500000 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END
Następnie utworzyłem następujące procedury składowane, aby przeprowadzić proste testy porównawcze SELECT
, SELECT
z LIKE
i sortowanie ( SELECT
z ORDER BY
):
CREATE PROCEDURE benchmark_simple_select()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description = 'test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_select_like()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description LIKE '%test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_order_by()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE ID > FLOOR(1 + RAND() * (400000 - 1))
ORDER BY Description COLLATE utf8_general_ci LIMIT 1000;
SET i = i + 1;
IF i = 10 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
W procedurach przechowywanych stosuje się powyższe utf8_general_ci
zestawienie, ale oczywiście podczas testów użyłem zarówno utf8_general_ci
i utf8_unicode_ci
.
Każdą procedurę przechowywaną wywołałem 5 razy dla każdego zestawienia (5 razy dla utf8_general_ci
i 5 razy dla utf8_unicode_ci
), a następnie obliczyłem wartości średnie.
Moje wyniki to:
benchmark_simple_select()
utf8_general_ci
: 9,957 ms utf8_unicode_ci
: 10 271 ms W tym teście używanie utf8_unicode_ci
jest wolniejsze niż utf8_general_ci
o 3,2%.
benchmark_select_like()
utf8_general_ci
: 11441 ms utf8_unicode_ci
: 12,811 ms W tym teście używanie utf8_unicode_ci
jest wolniejsze niż utf8_general_ci
o 12%.
benchmark_order_by()
utf8_general_ci
: 11944 ms utf8_unicode_ci
: 12887 ms W tym teście używanie utf8_unicode_ci
jest wolniejsze niż utf8_general_ci
o 7,9%.
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 ...
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ć.
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.
utf8_unicode_ci
i udawaj, że ten drugi nie istnieje.
utf8_general_ci
może być dla ciebie
Zobacz instrukcję mysql, sekcja Zestawy znaków Unicode :
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.
utf8_unicode_ci
i udawaj, że uszkodzona wersja z błędami nie istnieje.
0
a 1
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 754
1/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.
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 L
i 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_ci
tobie masz i != ı
, ale w utf8mb4_general_ci
nim 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 ß=ss
w utf8mb4_unicode_ci
któ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 .
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 /