В чем разница между utf8_general_ci и utf8_unicode_ci
-
12-09-2019 - |
Вопрос
Между utf8_general_ci
и utf8_unicode_ci
, есть ли какие-либо различия в плане производительности?
Решение
Эти два параметра сортировки предназначены для кодировки символов UTF-8.Различия заключаются в том, как текст сортируется и сравнивается.
Примечание:Начиная с MySQL 5.5.3, вы должны использовать utf8mb4
вместо того , чтобы utf8
.Они оба относятся к кодировке UTF-8, но более старая utf8
имел специфичное для MySQL ограничение, запрещающее использование символов, пронумерованных выше 0xFFFD.
Ключевые отличия
utf8mb4_unicode_ci
основан на официальных правилах Unicode для универсальной сортировки и сравнения, которые обеспечивают точную сортировку на широком спектре языков.utf8mb4_general_ci
это упрощенный набор правил сортировки, цель которого - работать как можно лучше, используя при этом множество коротких путей, направленных на повышение скорости.Это не соответствует правилам Unicode и приведет к нежелательной сортировке или сравнению в некоторых ситуациях, например, при использовании определенных языков или символов.На современных серверах этот прирост производительности будет практически незначительным.Он был разработан в то время, когда производительность серверов составляла лишь крошечную долю производительности процессора современных компьютеров.
Примечание:в настоящее время существует обновленная версия utf8mb4_unicode_ci
вызванный utf8mb4_0900_ai_ci
- это основано на изменениях в Unicode версии 9.0, а также, по-видимому, быстрее.Он принимает новую схему именования, согласно которой 0900
является версией Unicode и ai
означает, что акцент не чувствителен - как и предыдущий utf8mb4_unicode_ci
, ударения в письмах не считаются значимыми.
Преимущества utf8mb4_unicode_ci
закончился utf8mb4_general_ci
utf8mb4_unicode_ci
, который использует правила Unicode для сортировки и сравнения, использует довольно сложный алгоритм для правильной сортировки в широком диапазоне языков и при использовании широкого спектра специальных символов.Эти правила должны учитывать языковые соглашения;не все сортируют своих персонажей в том, что мы бы назвали "алфавитным порядком".
Что касается латинских (то есть "европейских") языков, то нет большой разницы между сортировкой в Юникоде и упрощенным utf8mb4_general_ci
сортировка в MySQL, но все же есть несколько отличий:
Например, параметры сортировки в Юникоде сортируют "β" как "ss", а "Œ" как "OE", как обычно хотели бы люди, использующие эти символы, тогда как
utf8mb4_general_ci
сортирует их как отдельные символы (предположительно, как "s" и "e" соответственно).Некоторые символы Юникода определены как игнорируемые, что означает, что они не должны учитываться при сортировке, и вместо этого сравнение должно перейти к следующему символу.
utf8mb4_unicode_ci
обрабатывает их должным образом.
В нелатинских языках, таких как азиатские языки или языки с разными алфавитами, может быть много Еще различия между сортировкой в Юникоде и упрощенным utf8mb4_general_ci
сортировка.Пригодность utf8mb4_general_ci
это будет сильно зависеть от используемого языка.Для некоторых языков это будет совершенно неадекватно.
Что вы должны использовать?
Почти наверняка нет причин использовать utf8mb4_general_ci
больше того, поскольку мы оставили позади момент, когда скорость процессора достаточно низкая, чтобы разница в производительности была важной.Ваша база данных почти наверняка будет ограничена другими узкими местами, помимо этого.
В прошлом некоторые люди рекомендовали использовать utf8mb4_general_ci
за исключением случаев, когда точная сортировка была бы достаточно важна, чтобы оправдать затраты на производительность.Сегодня эти затраты на производительность практически исчезли, и разработчики более серьезно относятся к интернационализации.
Можно привести аргумент, что если скорость для вас важнее точности, вы можете с таким же успехом вообще не выполнять сортировку.Тривиально ускорить алгоритм, если вам не нужно, чтобы он был точным.Итак, utf8mb4_general_ci
это компромисс, который, вероятно, не нужен по соображениям скорости и, вероятно, также не подходит по соображениям точности.
Еще одна вещь, которую я добавлю, - это то, что даже если вы знаете, что ваше приложение поддерживает только английский язык, ему все равно может потребоваться обрабатывать имена людей, которые часто могут содержать символы, используемые на других языках, правильная сортировка которых не менее важна.Использование правил Unicode для всего помогает добавить уверенности в том, что очень умные сотрудники Unicode очень усердно работали над тем, чтобы сортировка работала должным образом.
Что означают эти части
Во-первых, ci
предназначен для без учета регистра сортировка и сравнение.Это означает, что он подходит для текстовых данных, и регистр не важен.Другими типами сортировки являются cs
(с учетом регистра) для текстовых данных, где важен регистр, и bin
, для тех случаев, когда кодировка должна совпадать, бит в бит, что подходит для полей, которые действительно являются закодированными двоичными данными (включая, например, Base64).Сортировка с учетом регистра приводит к некоторым странным результатам, а сравнение с учетом регистра может привести к дублированию значений, отличающихся только регистром букв, поэтому параметры сортировки с учетом регистра не в пользу текстовых данных - если для вас важен регистр, то, вероятно, также важны игнорируемые знаки препинания и так далее, и двоичная сортировка может быть более подходящей.
Далее, unicode
или general
относится к конкретным правилам сортировки и сравнения - в частности, к способу нормализации или сравнения текста.Существует много различных наборов правил для кодировки символов utf8mb4, с unicode
и general
быть двумя, которые пытаются хорошо работать на всех возможных языках, а не на одном конкретном.Различия между этими двумя наборами правил являются предметом данного ответа.Обратите внимание, что новые наборы правил включают 0900
ссылаясь на Unicode 9.0, и unicode_520
ссылка на Unicode 5.2.
И, наконец,, utf8mb4
это, конечно, кодировка символов, используемая внутри компании.В этом ответе я говорю только о кодировках на основе Unicode.
Другие советы
Я хотел знать, в чем разница в производительности между использованием utf8_general_ci
и utf8_unicode_ci
, но я не нашел никаких бенчмарков, перечисленных в Интернете, поэтому решил создать бенчмарки сам.
Я создал очень простую таблицу с 500 000 строками:
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
Затем я создал следующие хранимые процедуры для тестирования simple SELECT
, SELECT
с LIKE
, и сортировка (SELECT
с 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;
В описанных выше хранимых процедурах utf8_general_ci
используется сопоставление, но, конечно, во время тестов я использовал оба варианта utf8_general_ci
и utf8_unicode_ci
.
Я вызывал каждую хранимую процедуру 5 раз для каждой сортировки (5 раз для utf8_general_ci
и 5 раз для utf8_unicode_ci
), а затем вычислили средние значения.
Мои результаты таковы:
benchmark_simple_select()
- с
utf8_general_ci
:9,957 мс - с
utf8_unicode_ci
:10,271 мс
В этом бенчмарке используется utf8_unicode_ci
происходит медленнее, чем utf8_general_ci
на 3,2%.
benchmark_select_like()
- с
utf8_general_ci
:11,441 мс - с
utf8_unicode_ci
:12,811 мс
В этом бенчмарке используется utf8_unicode_ci
происходит медленнее, чем utf8_general_ci
на 12%.
benchmark_order_by()
- с
utf8_general_ci
:11,944 мс - с
utf8_unicode_ci
:12,887 мс
В этом бенчмарке используется utf8_unicode_ci
происходит медленнее, чем utf8_general_ci
на 7,9%.
Этот пост описывает это очень хорошо.
Короче говоря:utf8_unicode_ci использует алгоритм сортировки в Юникоде, как определено в стандартах Юникода, тогда как utf8_general_ci - это более простой порядок сортировки, который приводит к "менее точным" результатам сортировки.
Смотрите руководство по mysql, Наборы символов Юникода Раздел:
Для любого набора символов 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 будет быстрее, потому что потребуется меньше вычислений.
В кратких словах:
Если вам нужен лучший порядок сортировки - используйте utf8_unicode_ci
(это предпочтительный метод),
но если вы крайне заинтересованы в производительности - используйте utf8_general_ci
, но знайте, что он немного устарел.
Различия в плане производительности очень незначительны.
Некоторые подробности (PL)
Как мы можем прочесть здесь (Питер Гулуцан) есть разница при сортировке / сравнении польской буквы "L" (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
.Ни одна из этих программ не является лучшей или хуже - это зависит от ваших потребностей.