В чем разница между utf8_general_ci и utf8_unicode_ci
Между utf8_general_ci
а также utf8_unicode_ci
Есть ли различия в производительности?
9 ответов
Эти два сопоставления предназначены для кодировки символов UTF-8. Различия в том, как текст сортируется и сравнивается.
Примечание: начиная с MySQL 5.5.3 вы должны использовать utf8mb4
скорее, чем utf8
, Они оба относятся к кодировке UTF-8, но более старые utf8
имеет специфичное для MySQL ограничение, запрещающее использование символов с номерами выше 0xFFFD.
точность
utf8mb4_unicode_ci
основан на стандарте Unicode для сортировки и сравнения, который точно сортирует на самых разных языках.utf8mb4_general_ci
не в состоянии реализовать все правила сортировки Unicode, что приведет к нежелательной сортировке в некоторых ситуациях, например при использовании определенных языков или символов.Спектакль
utf8mb4_general_ci
быстрее при сравнении и сортировке, потому что это требует кучу ярлыков, связанных с производительностью.На современных серверах это повышение производительности будет практически незначительным. Он был разработан в то время, когда серверы имели небольшую долю производительности ЦП современных компьютеров.
utf8mb4_unicode_ci
, который использует правила Unicode для сортировки и сравнения, использует довольно сложный алгоритм для правильной сортировки в широком диапазоне языков и при использовании широкого диапазона специальных символов. Эти правила должны учитывать языковые соглашения; не каждый сортирует своих персонажей в том, что мы назвали бы "алфавитным порядком".
Что касается латиницы (то есть "европейских") языков, то нет большой разницы между сортировкой Unicode и упрощенной utf8mb4_general_ci
сортировка в MySQL, но есть еще несколько отличий:
Например, параметры сортировки Unicode сортируют "ß", как "ss", и "Œ", как "OE", как обычно хотят люди, использующие эти символы, тогда как
utf8mb4_general_ci
сортирует их как отдельные символы (предположительно, как "s" и "e" соответственно).Некоторые символы Unicode определены как игнорируемые, что означает, что они не должны учитываться в порядке сортировки, и сравнение должно перейти к следующему символу.
utf8mb4_unicode_ci
обращается с этим правильно.
В нелатинских языках, таких как азиатские языки или языки с разными алфавитами, может быть намного больше различий между сортировкой Unicode и упрощенной utf8mb4_general_ci
сортировка. Пригодность utf8mb4_general_ci
будет сильно зависеть от используемого языка. Для некоторых языков это будет совершенно неадекватно.
Что вы должны использовать?
Почти наверняка нет причин использовать utf8mb4_general_ci
больше, поскольку мы оставили точку, когда скорость процессора достаточно низкая, чтобы разница в производительности была важной. Ваша база данных почти наверняка будет ограничена другими узкими местами, кроме этой.
Разница в производительности будет ощутима только в крайне специализированных ситуациях, и если это вы, вы, вероятно, уже знаете об этом. Если вы испытываете медленную сортировку, почти во всех случаях это будет проблемой с вашими индексами / планом запросов. Изменение функции сортировки не должно занимать первое место в списке проблем, требующих устранения.
В прошлом некоторые люди рекомендовали использовать utf8mb4_general_ci
кроме случаев, когда точная сортировка будет достаточно важной, чтобы оправдать затраты производительности. Сегодня эта производительность практически исчезла, и разработчики относятся к интернационализации более серьезно.
Еще одну вещь, которую я добавлю, это то, что даже если вы знаете, что ваше приложение поддерживает только английский язык, ему все равно может потребоваться работать с именами людей, которые часто могут содержать символы, используемые в других языках, для которых столь же важно правильно сортировать, Использование правил Unicode для всего помогает добавить душевного спокойствия, что очень умные люди Unicode очень усердно работали, чтобы заставить сортировку работать правильно.
Я хотел знать, в чем разница в производительности между использованием utf8_general_ci и utf8_unicode_ci, но я не нашел никаких тестов в Интернете, поэтому я решил создать тесты самостоятельно.
Я создал очень простую таблицу с 500000 строк:
CREATE TABLE test(
ID INT(11) DEFAULT NULL,
Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
Затем я заполнил его случайными данными, запустив эту хранимую процедуру:
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
Затем я создал следующие хранимые процедуры для сравнения простого SELECT, SELECT с LIKE и сортировки (SELECT с ORDER BY):
CREATE 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
В хранимых процедурах выше используется сортировка utf8_general_ci, но, конечно, во время тестов я использовал как utf8_general_ci, так и utf8_unicode_ci.
Я вызывал каждую хранимую процедуру 5 раз для каждого сопоставления (5 раз для utf8_general_ci и 5 раз для utf8_unicode_ci), а затем вычислял средние значения.
Мои результаты:
benchmark_simple_select() с utf8_general_ci: 9957 мс
benchmark_simple_select() с utf8_unicode_ci: 10271 мс
В этом тесте использование utf8_unicode_ci медленнее, чем utf8_general_ci на 3,2%.
benchmark_select_like() с utf8_general_ci: 11441 мс
benchmark_select_like() с utf8_unicode_ci: 12811 мс
В этом тесте использование utf8_unicode_ci медленнее, чем utf8_general_ci, на 12%.
benchmark_order_by() с utf8_general_ci: 11944 мс
benchmark_order_by() с utf8_unicode_ci: 12887 мс
В этом тесте использование utf8_unicode_ci медленнее, чем utf8_general_ci на 7,9%.
Этот пост описывает это очень хорошо.
Вкратце: utf8_unicode_ci использует алгоритм сопоставления Unicode, как определено в стандартах Unicode, тогда как utf8_general_ci - более простой порядок сортировки, который приводит к "менее точным" результатам сортировки.
См. Руководство по mysql, раздел " Наборы символов Unicode ":
Для любого набора символов Unicode операции, выполняемые с использованием параметров сортировки _general_ci, выполняются быстрее, чем операции с параметрами сортировки _unicode_ci. Например, сравнения для сопоставления utf8_general_ci выполняются быстрее, но немного менее корректно, чем сравнения для utf8_unicode_ci. Причина этого заключается в том, что utf8_unicode_ci поддерживает сопоставления, такие как расширения; то есть, когда один символ сравнивается как равный комбинации других символов. Например, в немецком и некоторых других языках "ß" равно "ss". utf8_unicode_ci также поддерживает сокращения и игнорируемые символы. utf8_general_ci - это устаревшая сортировка, которая не поддерживает расширения, сокращения или игнорируемые символы. Он может делать только однозначное сравнение между персонажами.
Таким образом, чтобы подвести итог, utf_general_ci использует меньший и менее правильный (согласно стандарту) набор сравнений, чем utf_unicode_ci, который должен реализовать весь стандарт. Набор general_ci будет быстрее, потому что требуется меньше вычислений.
Есть две большие разницы в сортировке и сопоставлении символов:
Сортировка:
utf8mb4_general_ci
удаляет все акценты и сортирует по одному, что может привести к неверным результатам сортировки.utf8mb4_unicode_ci
сортировки точные.
Соответствие символов
Они по-разному соответствуют персонажам.
Например, в utf8mb4_unicode_ci
у тебя есть i != ı
, но в utf8mb4_general_ci
он держит ı=i
.
Например, представьте, что у вас есть строка с name="Yılmaz"
. потом
select id from users where name='Yilmaz';
вернет строку, если коллокация utf8mb4_general_ci
, но если он совмещен с utf8mb4_unicode_ci
он не вернет строку!
С другой стороны, у нас есть a=ª
а также ß=ss
в utf8mb4_unicode_ci
что не так в utf8mb4_general_ci
. Итак, представьте, что у вас есть скандал сname="ªßi"
, тогда
select id from users where name='assi';
вернет строку, если коллокация utf8mb4_unicode_ci
, но не вернет строку, если для коллокации установлено значениеutf8mb4_general_ci
.
Полный список совпадений для каждого словосочетания можно найти здесь.
Некоторые детали (PL)
Как мы можем прочитать здесь (Питер Гулутзан), существует разница в сортировке / сравнении польской буквы "Ł" (L с штрихом - html esc: Ł
) (нижний регистр: "ł" - html esc: ł
) - имеем следующее предположение:
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
На польском языке буква Ł
после письма L
и раньше M
, Ни одна из этих кодировок не является лучше или хуже - это зависит от ваших потребностей.
Вкратце:
Если вам нужен лучший порядок сортировки - используйте utf8_unicode_ci
(это предпочтительный метод),
но если вы крайне заинтересованы в производительности - используйте utf8_general_ci
, но знайте, что это немного устарело.
Различия с точки зрения производительности очень незначительны.
Согласно этому сообщению, при использовании utf8mb4_general_ci вместо utf8mb4_unicode_ci в MySQL 5.7 наблюдается значительный выигрыш в производительности:https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact-on-mysql-performance/
Приведенные выше комментарии предполагают, что нет причин использоватьutf8_general*
. Однако для японцев это может быть не так.
С МариаДБutf8mb4_ja_0900_as_cs
недоступен, поэтому вы должны использовать один из юникодных или общих параметров. Однако,unicode
относится к звонким и глухим звукам одинаково. Например, びよういん (косметолог) считается равным びょういん (больница). Это явно неправильное поведение.
> select strcmp('が', 'か' collate utf8mb4_unicode_ci); #0
> strcmp('びよういん', 'びょういん' collate utf8mb4_unicode_520_ci); #0
в то время как генерал дает
> select strcmp('が', 'か' collate utf8mb4_general_ci); #1
Другими словами, Unicode обрабатывает озвученную и глухую кану одинаково. Имхо, это нежелательно.
Изменить: может быть лучше использоватьuca1400_ai_cs
который доступен в более новых версиях MariaDB, и правильно выполните приведенные выше сопоставления.