UTF-8: Ogólne? Kosz? Unicode?

279

Próbuję dowiedzieć się, jakiego sortowania powinienem używać dla różnych typów danych. 100% treści, które będę przechowywać, jest przesłane przez użytkownika.

Rozumiem, że powinienem używać UTF-8 General CI (bez rozróżniania wielkości liter) zamiast UTF-8 Binary. Nie mogę jednak znaleźć wyraźnego rozróżnienia między CI UTF-8 General CI a CI UTF-8 Unicode.

  1. Czy powinienem przechowywać treści przesłane przez użytkowników w kolumnach UTF-8 General lub UTF-8 Unicode CI?
  2. Do jakiego rodzaju danych miałoby zastosowanie UTF-8 Binary?
Dolph
źródło
16
Uwaga dodatkowa, ale zamiast tego utf8użyj utf8mb4zamiast tego, aby uzyskać pełną obsługę UTF-8. Komentując tutaj, ponieważ odpowiedzi na to popularne pytanie nie rozwiązują tego. mathiasbynens.be/notes/mysql-utf8mb4
Steven R. Loomis
Jeśli chcesz składać sprawy, ale wrażliwość na akcent, zgłoś prośbę na stronie bugs.mysql.com .
Rick James
Lub kliknij „ Affects Me” na stronie bugs.mysql.com/bug.php?id=58797 i dodaj komentarz.
Rick James,

Odpowiedzi:

299

Ogólnie rzecz biorąc, utf8_general_ci jest szybszy niż utf8_unicode_ci , ale mniej poprawny.

Oto różnica:

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 porównania 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.

Cytat z: http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html

Aby uzyskać bardziej szczegółowe wyjaśnienia, przeczytaj następujący post z forów MySQL: http://forums.mysql.com/read.php?103,187048,188748

Jeśli chodzi o utf8_bin: Zarówno utf8_general_ci, jak i utf8_unicode_ci wykonują porównanie bez rozróżniania wielkości liter. W przeciwieństwie do tego w utf8_bin rozróżniana jest wielkość liter (między innymi różnicami), ponieważ porównuje wartości binarne znaków.

Sagi
źródło
2
Myślę, że jeśli nie masz dobrego powodu, aby używać _unicode_ci, to użyj _general_ci.
Sagi
4
To jednak tak naprawdę nie odpowiada na to pytanie dogłębnie. Jaka jest dokładnie różnica między tymi zestawieniami?
Pekka
4
Masz rację, dokładna różnica nie została tutaj podana dla uproszczenia. Dodałem link do posta z dokładną różnicą.
Sagi,
NB show collation;pozwala zobaczyć domyślne sortowanie dla każdego zestawu znaków. 5.1 pokazuje utf8_general_cijako domyślny dla utf8.
David Carboni,
9
Czy są jakieś zasoby, które mogłyby pogłębić rzeczywistą różnicę prędkości między dwoma zestawieniami? Czy mówimy o spadku wydajności o 0,1%, czy o 10%?
Emphram Stavanger
90

Należy również pamiętać o tym, że w przypadku utf8_general_ci podczas używania pola varchar jako indeksu unikalnego lub podstawowego wstawienie 2 wartości, takich jak „a” i „á”, spowodowałoby powtórzenie błędu klucza.

Alex Hepp
źródło
3
Dzięki, jest to przydatne, aby uniknąć podobnych nazw użytkowników (np. Jeśli „jose” istnieje, nie chciałbym, aby ktoś inny utworzył użytkownika „josé”). Uwaga: dotyczy to również większości zestawień utf8 (z wyjątkiem utf8_bin). Najpewniejszym / najbezpieczniejszym / najbardziej kompleksowym jestutf8_unicode_ci
Costa
2
Korzystam z utf8_bin, w którym chcę, aby jose i josé były wyróżnione w indeksie. Na przykład kolumna rejestrująca operacje wyszukiwania / zamiany, w których użytkownik mógł zdecydować się na wyszukiwanie josé i zastąpienie go jose. (Piszę program do arkuszy kalkulacyjnych)
Buttle Butkus
33
  • utf8_binporównuje bity na ślepo. Bez składania skrzynek, bez usuwania akcentów.
  • utf8_general_ciporównuje jeden bajt z jednym bajtem. Składa skrzynie i usuwanie akcentów, ale nie ma 2-znakowych porównań: ijnie jest równy ijw tym zestawieniu.
  • utf8_*_cijest zbiorem reguł specyficznych dla języka, ale poza tym jest podobny unicode_ci. Niektóre przypadki szczególne: Ç, Č, ch,ll
  • utf8_unicode_ciw porównaniu porównuje się ze starym standardem Unicode. ij= ij, ale ae! =æ
  • utf8_unicode_520_cijest zgodny z nowszym standardem Unicode. ae=æ

Zobacz tabelę zestawień, aby uzyskać szczegółowe informacje na temat tego, co jest równe co w różnych zestawieniach utf8.

utf8, zgodnie z definicją MySQL, jest ograniczony do 1- do 3-bajtowych kodów utf8. To pomija Emoji i niektóre chińskie. Dlatego naprawdę powinieneś się przestawić na, utf8mb4jeśli chcesz wyjść daleko poza Europę.

Powyższe punkty dotyczą utf8mb4, po odpowiedniej zmianie pisowni. Idąc dalej utf8mb4i utf8mb4_unicode_520_cisą preferowane.

  • utf16 i utf32 są wariantami utf8; nie ma dla nich praktycznie żadnego pożytku.
  • ucs2 jest bliższy „Unicode” niż „utf8”; praktycznie nie ma z tego pożytku.
Rick James
źródło
1
Re „stay tuned”: 8,0 zestawień pokazuje, jak różne postacie, dyftongi itp. Porównują w zestawieniach 8.0 utf8mb4; utf8 jest w większości taki sam.
Rick James
A 8.0 zestawień jest taktowanych znacznie szybciej niż 5.x.
Rick James,
byłoby miło, gdyby ta strona zawierała utf8mb4_bin na górze. Wiem, że w ogóle nie dopasowuje postaci, ale jest dobry dla początkujących.
Henk Poley
6

Naprawdę przetestowałem zapisywanie wartości takich jak „é” i „e” w kolumnie z unikalnym indeksem i powodują one zduplikowany błąd zarówno w „utf8_unicode_ci”, jak i „utf8_general_ci”. Możesz zapisać je tylko w kolumnie „utf8_bin”.

A mysql docs (w http://dev.mysql.com/doc/refman/5.7/en/charset-applications.html ) sugeruje w swoich przykładach zestawienie „utf8_general_ci”.

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
vitalii
źródło
1
Zrobiłem szybki test w tej sprawie i wydaje się być dokładny. Oba układy zachowują się tak samo, jeśli chodzi o unikalny klucz w kolumnie i wartości z tyldami i tym podobnymi.
MirroredFate
@MirroredFate OK, powinienem tam dodać, że kolumna powinna mieć unikalny indeks powodujący ten błąd. To sugeruje w mojej odpowiedzi.
vitalii
3

Zaakceptowana odpowiedź jest nieaktualna.

Jeśli używasz MySQL 5.5.3+, użyj utf8mb4_unicode_cizamiast, utf8_unicode_ciaby upewnić się, że znaki wpisywane przez użytkowników nie będą powodować błędów.

utf8mb4obsługuje na przykład emoji, utf8ale może dostarczyć setki błędów związanych z kodowaniem, takich jak:

Incorrect string value: ‘\xF0\x9F\x98\x81…’ for column ‘data’ at row 1

Marwann
źródło
Ta odpowiedź (poprawnie) rozwiązuje problemy z kodowaniem Emoji (i niektórych chińskich). Ale wydaje się, że pytanie koncentruje się na sortowaniu. utf8mb4_unicode_citraktuje (jak sądzę) wszystkie emoji jako równe. utf8mb4_unicode_520_ciwydaje zamówienie Emoji.
Rick James