UTF-8: генерал? Бен? Unicode?

279

Я пытаюсь выяснить, какую сортировку я должен использовать для различных типов данных. 100% содержимого, которое я буду хранить, отправлено пользователем.

Насколько я понимаю, я должен использовать UTF-8 General CI (без учета регистра) вместо UTF-8 Binary. Однако я не могу найти четкого различия между UTF-8 General CI и UTF-8 Unicode CI.

  1. Должен ли я хранить пользовательский контент в столбцах UTF-8 General или UTF-8 Unicode CI?
  2. К какому типу данных будет применяться UTF-8 Binary?
Дольф
источник
16
Примечание, но вместо этого utf8используйте utf8mb4вместо полной поддержки UTF-8. Комментировать здесь, потому что ответы на этот популярный вопрос не решают эту проблему. mathiasbynens.be/notes/mysql-utf8mb4
Стивен Р. Лумис
Если вы хотите сложить регистр, но чувствительность к акценту, пожалуйста, отправьте запрос на bugs.mysql.com .
Рик Джеймс
Или нажмите «Влияет на меня» на bugs.mysql.com/bug.php?id=58797 и добавьте комментарий.
Рик Джеймс

Ответы:

299

В общем, utf8_general_ci быстрее, чем utf8_unicode_ci , но менее правильно.

Вот разница:

Для любого набора символов Unicode операции, выполняемые с использованием параметров сортировки _general_ci, выполняются быстрее, чем операции с параметрами сортировки _unicode_ci . Например, сравнения для сопоставления utf8_general_ci выполняются быстрее, но немного менее корректно, чем сравнения для utf8_unicode_ci. Причина этого в том, что utf8_unicode_ci поддерживает такие отображения, как расширения; то есть, когда один символ сравнивается как равный комбинации других символов. Например, в немецком и некоторых других языках «ß» равно «ss». utf8_unicode_ci также поддерживает сокращения и игнорируемые символы. utf8_general_ci - это устаревшая сортировка, которая не поддерживает расширения, сокращения или игнорируемые символы. Он может делать только однозначное сравнение между персонажами.

Цитируется по адресу : http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html

Для более подробного объяснения, пожалуйста, прочитайте следующий пост с форумов MySQL: http://forums.mysql.com/read.php?103,187048,188748

Что касается utf8_bin: и utf8_general_ci, и utf8_unicode_ci выполняют сравнение без учета регистра. В отличие от этого , utf8_bin чувствителен к регистру (среди прочих различий), потому что он сравнивает двоичные значения символов.

Саги
источник
2
Я думаю, что если у вас нет веской причины использовать _unicode_ci, то используйте _general_ci.
Саги
4
Это действительно не отвечает на вопрос в глубине, хотя. В чем разница между этими сопоставлениями?
Пекка
4
Вы правы, точная разница здесь не указана ради простоты. Я добавил ссылку на пост с точной разницей.
Саги
NB show collation;позволяет просматривать параметры сортировки по умолчанию для каждого набора символов. 5.1 показывает utf8_general_ciпо умолчанию для utf8.
Дэвид Карбони
9
Существуют ли какие-либо ресурсы, которые бы углублялись в фактическую разницу в скорости между двумя сопоставлениями? Мы говорим о снижении производительности на 0,1% или на 10%?
Эфрам Ставангер,
90

Вам также следует учитывать тот факт, что при использовании utf8_general_ci при использовании поля varchar в качестве уникального или первичного индекса при вставке двух значений, таких как 'a' и 'á', возникнет ошибка дублирующегося ключа.

Алекс Хепп
источник
3
Спасибо, это полезно, чтобы избежать подобных имен пользователей (например, если существует «jose», я бы не хотел, чтобы кто-то еще создавал пользователя «josé»). Примечание: это также верно для большинства сопоставлений utf8 (кроме utf8_bin). Самый надежный / самый безопасный / самый полныйutf8_unicode_ci
Коста
2
Я использую utf8_bin, где я хочу, чтобы Хосе и Хосе были выделены в индексе. Например, столбец, в котором записываются операции поиска / замены, где пользователь, возможно, решил поискать josé и заменить его на jose. (Я пишу программу для работы с электронными таблицами)
Buttle Butkus
33
  • utf8_binсравнивает биты вслепую. Нет складывания, без зачистки.
  • utf8_general_ciсравнивает один байт с одним байтом. Это делает сворачивание падежа и удаление акцента, но без сравнения двух символов: в этом сопоставлении они ijне равны ij.
  • utf8_*_ciэто набор правил для конкретного языка, но в остальном вроде unicode_ci. Некоторые особые случаи: Ç, Č, ch,ll
  • utf8_unicode_ciследует старому стандарту Unicode для сравнения. ij= ij, но ae! =æ
  • utf8_unicode_520_ciследует более новому стандарту Unicode. aeзнак равноæ

См. Таблицу сопоставления для деталей о том, что равно чему в различных сопоставлениях utf8.

utf8, как определено MySQL , ограничено 1–3-байтовыми кодами utf8. Это оставляет эмодзи и некоторые китайцы. Таким образом, вы действительно должны переключиться на, utf8mb4если вы хотите выйти далеко за пределы Европы.

Вышеуказанные пункты применяются к utf8mb4, после соответствующего изменения правописания. Идем вперед utf8mb4и utf8mb4_unicode_520_ciпредпочитаем.

  • utf16 и utf32 являются вариантами на utf8; для них практически нет смысла.
  • ucs2 ближе к "Unicode", чем "utf8"; это практически бесполезно.
Рик Джеймс
источник
1
«Оставайтесь с нами»: сопоставления 8.0 показывают, как различные символы, дифтонги и т. Д. Сравниваются в сопоставлениях 8.0 utf8mb4; utf8 в основном то же самое.
Рик Джеймс
И 8,0 сопоставления работают значительно быстрее, чем 5.x.
Рик Джеймс
было бы хорошо, если бы эта страница перечисляла utf8mb4_bin вверху. Я знаю, что это совсем не соответствует характеру, но это хорошо для новичков.
Хенк Поли,
6

Действительно, я протестировал сохранение значений, таких как 'é' и 'e', ​​в столбце с уникальным индексом, и они вызвали двойную ошибку как в utf8_unicode_ci, так и в utf8_general_ci. Вы можете сохранить их только в сопоставленном столбце utf8_bin.

И документы mysql (в http://dev.mysql.com/doc/refman/5.7/en/charset-applications.html ) предлагают в свои примеры набор параметров utf8_general_ci.

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
виталий
источник
1
Я сделал быструю проверку на это, и это кажется точным. Оба сопоставления ведут себя одинаково, когда дело доходит до уникального ключа в столбце и значений с тильдами и тому подобным.
MirroredFate
@MirroredFate Хорошо, я должен добавить туда, что столбец должен иметь уникальный индекс, вызывающий эту ошибку. Это подразумевает в моем ответе.
Виталий
3

Принятый ответ устарел.

Если вы используете MySQL 5.5.3+, используйте utf8mb4_unicode_ciвместоutf8_unicode_ci чтобы символы, набранные вашими пользователями, не ошибок.

utf8mb4например, поддерживает emojis, тогда как utf8может дать вам сотни ошибок, связанных с кодировкой, таких как:

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

Marwann
источник
Этот ответ (правильно) решает проблемы с кодировкой эмодзи (и некоторых китайских). Но вопрос, кажется, сосредоточен на сопоставлении. utf8mb4_unicode_ciрассматривает (я думаю) все эмодзи как равные. utf8mb4_unicode_520_ciдает приказ Emoji.
Рик Джеймс