Zastanawiam się, czy istnieje „najlepszy” wybór do sortowania w MySQL dla ogólnej witryny, w której nie jesteś w 100% pewien, co zostanie wprowadzone? Rozumiem, że wszystkie kodowania powinny być takie same, takie jak MySQL, Apache, HTML i cokolwiek w PHP.
W przeszłości ustawiałem PHP na wyświetlanie w „UTF-8”, ale które zestawienie pasuje do tego w MySQL? Ja myślę, że to jeden z tych, UTF-8, ale użyłem utf8_unicode_ci
, utf8_general_ci
i utf8_bin
wcześniej.
Odpowiedzi:
Główną różnicą jest dokładność sortowania (przy porównywaniu znaków w języku) i wydajność. Jedynym specjalnym jest utf8_bin, który służy do porównywania znaków w formacie binarnym.
utf8_general_ci
jest nieco szybszy niżutf8_unicode_ci
, ale mniej dokładny (do sortowania). Specyficzny język kodowania utf8 (takie jakutf8_swedish_ci
) zawierają dodatkowe zasady językowe, które czynią je najbardziej dokładne sortowanie dla tych języków. Większość czasu używamutf8_unicode_ci
(wolę dokładność niż małe ulepszenia wydajności), chyba że mam dobry powód, aby preferować określony język.Możesz przeczytać więcej na temat określonych zestawów znaków Unicode w podręczniku MySQL - http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html
źródło
utf8_unicode_*
utf8mb4
iutf8mb4_unicode_520_ci
. Dają ci resztę chińskiego, a także ulepszone sortowanie.W rzeczywistości prawdopodobnie chcesz użyć
utf8_unicode_ci
lubutf8_general_ci
.utf8_general_ci
sortuje, usuwając wszystkie akcenty i sortując jak ASCIIutf8_unicode_ci
używa kolejności sortowania Unicode, więc sortuje poprawnie w większej liczbie językówJeśli jednak używasz tego tylko do przechowywania tekstu w języku angielskim, nie powinny się one różnić.
źródło
Bądź bardzo, bardzo świadomy tego problemu, który może wystąpić podczas używania
utf8_general_ci
.MySQL nie rozróżnia niektórych znaków w instrukcjach select, jeśli
utf8_general_ci
używane jest sortowanie. Może to prowadzić do bardzo nieprzyjemnych błędów - szczególnie na przykład w przypadku nazw użytkowników. W zależności od implementacji korzystającej z tabel bazy danych ten problem może pozwolić złośliwym użytkownikom na utworzenie nazwy użytkownika pasującej do konta administratora.Ten problem ujawnia się przynajmniej we wczesnych wersjach 5.x - nie jestem pewien, czy to zachowanie zmieniło się później.
Nie jestem DBA, ale aby uniknąć tego problemu, zawsze wybieram
utf8-bin
zamiast rozróżniania wielkości liter.Poniższy skrypt opisuje problem na przykładzie.
źródło
'value'
i'valUe'
. Cały sens zestawiania polega na tym, że zapewnia reguły (między innymi), gdy dwa ciągi są uważane za równe sobie.Najlepiej używać zestawu znaków
utf8mb4
z zestawieniemutf8mb4_unicode_ci
.Zestaw znaków
utf8
obsługuje tylko niewielką liczbę punktów kodowych UTF-8, około 6% możliwych znaków.utf8
obsługuje tylko Basic Multilingual Plane (BMP). Jest 16 innych samolotów. Każdy samolot zawiera 65 536 znaków.utf8mb4
obsługuje wszystkie 17 samolotów.MySQL skróci 4-bajtowe znaki UTF-8, co spowoduje uszkodzenie danych.
Zestaw
utf8mb4
znaków został wprowadzony w MySQL 5.5.3 w dniu 24.03.2010.Niektóre z wymaganych zmian w celu użycia nowego zestawu znaków nie są trywialne:
ROW_FORMAT=DYNAMIC
UWAGA: Przełączenie
Barracuda
zAntelope
, może wymagać ponownego uruchomienia usługi MySQL więcej niż raz.innodb_file_format_max
nie zmienia się aż po serwis MySQL została wznowiona do:innodb_file_format = barracuda
.MySQL używa starego
Antelope
formatu pliku InnoDB.Barracuda
obsługuje dynamiczne formaty wierszy, które będą potrzebne, jeśli nie chcesz trafić do błędów SQL podczas tworzenia indeksów i kluczy po przejściu na zestaw znaków:utf8mb4
Poniższy scenariusz został przetestowany na MySQL 5.6.17: Domyślnie MySQL jest skonfigurowany w następujący sposób:
Zatrzymaj usługę MySQL i dodaj opcje do istniejącego pliku my.cnf:
Przykładowa instrukcja SQL CREATE:
INDEX contact_idx (contact)
jeśliROW_FORMAT=DYNAMIC
został usunięty z instrukcji CREATE.UWAGA: Zmiana indeksu na ograniczenie do pierwszych 128 znaków
contact
eliminuje konieczność używania Barracuda zROW_FORMAT=DYNAMIC
Uwaga: gdy mówi
VARCHAR(128)
, że pole ma rozmiar , to nie jest 128 bajtów. Możesz użyć 128, 4-bajtowych znaków lub 128, 1-bajtowych znaków.Ta
INSERT
instrukcja powinna zawierać 4-bajtowy znak „poo” w 2 rzędzie:Możesz zobaczyć ilość miejsca zajmowanego przez
last
kolumnę:W adapterze bazy danych może być konieczne ustawienie zestawu znaków i sortowania dla połączenia:
W PHP byłoby to ustawione dla:
\PDO::MYSQL_ATTR_INIT_COMMAND
Bibliografia:
źródło
utf8mb4_unicode_520_ci
jest lepsza. W przyszłości będzieutf8mb4_unicode_800_ci
(lub coś takiego), ponieważ MySQL dogania standardy Unicode.Sortowanie wpływa na sposób sortowania danych i na porównanie łańcuchów. Oznacza to, że powinieneś użyć sortowania, którego oczekuje większość użytkowników.
Przykład z dokumentacji dla kodowania Unicode :
Tak więc - zależy to od oczekiwanej bazy użytkowników i tego, ile potrzebujesz poprawnego sortowania. Dla angielskiej bazy użytkowników
utf8_general_ci
powinno wystarczyć, dla innych języków, takich jak szwedzki, stworzono specjalne zestawienia.źródło
Zasadniczo zależy to od tego, jak myślisz o sznurku.
Zawsze używam utf8_bin z powodu problemu wskazanego przez Guusa. Moim zdaniem, jeśli chodzi o bazę danych, ciąg jest nadal tylko ciągiem. Ciąg jest liczbą znaków UTF-8. Postać ma reprezentację binarną, więc dlaczego musi znać język, którego używasz? Zwykle ludzie będą budować bazy danych dla systemów z zakresem dla witryn wielojęzycznych. Taki jest sens używania UTF-8 jako zestawu znaków. Jestem trochę purystą, ale myślę, że ryzyko błędu znacznie przewyższa niewielką przewagę, jaką możesz uzyskać przy indeksowaniu. Wszelkie reguły związane z językiem powinny być wykonywane na znacznie wyższym poziomie niż DBMS.
W moich książkach „wartość” nigdy nie powinna równać się „valúe”.
Jeśli chcę zapisać pole tekstowe i przeprowadzić wyszukiwanie bez rozróżniania wielkości liter, użyję funkcji łańcuchowych MYSQL z funkcjami PHP, takimi jak LOWER () i funkcja php strtolower ().
źródło
Do informacji tekstowych UTF-8 należy użyć,
utf8_general_ci
ponieważ ...utf8_bin
: porównaj ciągi według wartości binarnej każdego znaku w ciąguutf8_general_ci
: porównywanie ciągów przy użyciu ogólnych reguł językowych i porównań bez rozróżniania wielkości literalias powinno to przyspieszyć / zwiększyć wydajność / użyteczność wyszukiwania i indeksowania danych.
źródło
Przyjęta odpowiedź dość zdecydowanie sugeruje użycie utf8_unicode_ci, i chociaż w przypadku nowych projektów, które są świetne, chciałem odnieść się do moich niedawnych przeciwnych doświadczeń na wypadek, gdyby zaoszczędził trochę czasu.
Ponieważ utf8_general_ci jest domyślnym zestawieniem dla Unicode w MySQL, jeśli chcesz używać utf8_unicode_ci, musisz w wielu miejscach podać go .
Na przykład wszystkie połączenia klienckie mają nie tylko domyślny zestaw znaków (co ma dla mnie sens), ale także domyślne zestawienie (tzn. Zestawienie zawsze będzie domyślnie ustawione na utf8_general_ci dla Unicode).
Prawdopodobnie, jeśli użyjesz utf8_unicode_ci dla swoich pól, twoje skrypty łączące się z bazą danych będą musiały zostać zaktualizowane, aby wyraźnie wspomniały o pożądanym sortowaniu - w przeciwnym razie zapytania przy użyciu ciągów tekstowych mogą się nie powieść, gdy twoje połączenie używa domyślnego sortowania.
Konsekwencją jest to, że podczas konwersji istniejącego systemu dowolnej wielkości na Unicode / utf8 możesz zostać zmuszony do użycia utf8_general_ci z powodu sposobu, w jaki MySQL obsługuje wartości domyślne.
źródło
W przypadku wyróżnionym przez Guusa zdecydowanie zalecam użycie albo utf8_unicode_cs (rozróżnianie wielkości liter, ścisłe dopasowanie, porządkowanie w większości przypadków) zamiast utf8_bin (ścisłe dopasowanie, niepoprawne porządkowanie).
Jeśli pole ma być przeszukiwane, a nie dopasowane do użytkownika, użyj utf8_general_ci lub utf8_unicode_ci. W obu przypadkach nie jest rozróżniana wielkość liter, jeden będzie pasował do siebie („ß” jest równe „s”, a nie „ss”). Istnieją również wersje specyficzne dla języka, takie jak utf8_german_ci, w których dopasowanie z utratą jest bardziej odpowiednie dla określonego języka.
[Edytuj - prawie 6 lat później]
Nie polecam już zestawu znaków „utf8” na MySQL, a zamiast tego polecam zestaw znaków „utf8mb4”. Dopasowują się prawie całkowicie, ale pozwalają na trochę (dużo) więcej znaków Unicode.
Realistycznie MySQL powinien zaktualizować zestaw znaków „utf8” i odpowiednie sortowania, aby pasowały do specyfikacji „utf8”, ale zamiast tego osobny zestaw znaków i odpowiednie sortowania, aby nie wpływały na oznaczenie pamięci dla tych, którzy już używają ich niekompletnego zestawu znaków „utf8” .
źródło
utf8_unicode_cs
nie istnieje. Jedynym utf8 z rozróżnianiem wielkości liter jestutf8_bin
. Problem zutf8_bin
sortowaniem jest nieprawidłowy. Zobacz: stackoverflow.com/questions/15218077/…Uważam, że te zestawienia są pomocne. http://collation-charts.org/mysql60/ . Nie jestem jednak pewien, który jest używany utf8_general_ci.
Na przykład tutaj jest wykres dla utf8_swedish_ci. Pokazuje, które znaki interpretuje jako takie same. http://collation-charts.org/mysql60/mysql604.utf8_swedish_ci.html
źródło
W pliku do przesłania bazy danych dodaj następujący wiersz przed dowolnym wierszem:
Twój problem powinien zostać rozwiązany.
źródło
SET NAMES
bezpośrednie zapytania nie informuje klienta o kodowaniu i może zepsuć niektóre funkcje, takie jak przygotowane instrukcje w bardzo subtelny sposób.