Между 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
не реализует все правила сортировки Юникода, что приведет к нежелательной сортировке в некоторых ситуациях, например, при использовании определенных языков или символов.
Производительность
utf8mb4_general_ci
работает быстрее при сравнении и сортировке, потому что он принимает кучу ярлыков, связанных с производительностью.
На современных серверах это повышение производительности будет практически незначительным. Он был разработан в то время, когда серверы имели крошечную долю производительности процессора сегодняшних компьютеров.
utf8mb4_unicode_ci
, который использует правила Unicode для сортировки и сравнения, использует довольно сложный алгоритм для правильной сортировки в широком диапазоне языков и при использовании широкого спектра специальных символов. Эти правила должны учитывать языковые соглашения; не каждый сортирует своих персонажей в том, что мы будем называть "алфавитным порядком".
Что касается латинских (т.е. "европейских" ) языков, то нет большой разницы между сортировкой Юникода и упрощенной сортировкой utf8mb4_general_ci
в MySQL, но все еще есть несколько отличий:
Например, сортировка Unicode сортирует "ß" как "ss" и "Œ", например "OE", поскольку люди, использующие эти символы, обычно хотят, тогда как utf8mb4_general_ci
сортирует их как одиночные символы (предположительно "s" и "e" соответственно).
Некоторые символы Юникода определяются как невежественные, что означает, что они не должны рассчитывать на порядок сортировки, и сравнение должно перейти к следующему символу. utf8mb4_unicode_ci
обрабатывает их правильно.
В неязыковых языках, таких как азиатские языки или языки с разными алфавитами, может быть намного больше различий между сортировкой Юникода и упрощенной сортировкой utf8mb4_general_ci
. Пригодность utf8mb4_general_ci
будет в значительной степени зависеть от используемого языка. Для некоторых языков это будет довольно неадекватно.
Что вы должны использовать?
Почти нет причин использовать utf8mb4_general_ci
больше, так как мы оставили точку, где скорость процессора достаточно низкая, чтобы разница в производительности была важной. Ваша база данных почти наверняка будет ограничена другими узкими местами, чем это.
Разница в производительности будет только измеряться в чрезвычайно специализированных ситуациях, и если вы это знаете, вы, вероятно, уже знаете об этом. Если вы испытываете медленную сортировку, почти во всех случаях это будет проблемой для вашего плана индексов/запросов. Изменение функции сопоставления не должно быть высоким в списке вещей для устранения неполадок.
В прошлом некоторые люди рекомендовали использовать utf8mb4_general_ci
, за исключением случаев, когда точная сортировка будет достаточно важной, чтобы оправдать стоимость исполнения. Сегодня эта производительность почти полностью исчезла, и разработчики более серьезно относятся к интернационализации.
Еще одна вещь, которую я добавлю, заключается в том, что даже если вы знаете, что ваше приложение поддерживает только английский язык, ему все равно придется иметь дело с именами людей, которые часто могут содержать символы, используемые на других языках, в которых это так же важно правильно сортировать. Использование правил Юникода для всего помогает добавить душевное спокойствие, что очень умные люди Юникода очень усердно работали над корректной работой сортировки.
utf8_general_ci
: он просто не работает. Это возвращение к плохим старым временам ASCII-ступенек с пятидесятилетней давности. Сопоставление без учета регистра в Юникоде невозможно выполнить без карты сгиба из UCD. Например, «Σίσυφος» содержит три разные сигмы; или как строчная буква «TSCHüẞ» - «tschüβ», а прописная буква «tschüβ» - «TSCHÜSS». Вы можете быть правы, или вы можете быть быстрым. Поэтому вы должны использовать utf8_unicode_ci
, потому что если вас не волнует правильность, сделать тривиально бесконечно быстро.
LTRIM
/ RTRIM
?
Я хотел знать, какова разница в производительности между 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
Затем я создал следующие хранимые процедуры для сравнения простых SELECT, SELECT с LIKE и сортировки (SELECT with 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 ms
В этом тесте с использованием utf8_unicode_ci медленнее, чем utf8_general_ci на 3.2%.
benchmark_select_like() с utf8_general_ci: 11441 ms
benchmark_select_like() с utf8_unicode_ci: 12811 ms
В этом тесте с использованием utf8_unicode_ci медленнее, чем utf8_general_ci на 12%.
benchmark_order_by() с utf8_general_ci: 11944 ms
benchmark_order_by() с utf8_unicode_ci: 12887 ms
В этом тесте с использованием utf8_unicode_ci медленнее, чем utf8_general_ci на 7,9%.
utf8_general_ci
слишком мал, чтобы его стоило использовать.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
генерирует только ASCII, а не символы Unicode, которые будут обрабатываться алгоритмами сопоставления. 2) Description = 'test' COLLATE ...
и Description LIKE 'test%' COLLATE ...
обрабатывать только одну строку ("test") во время выполнения, не так ли? 3) В реальных приложениях столбцы, используемые при упорядочении, вероятно, будут проиндексированы, и скорость индексации для разных сопоставлений с реальным текстом, отличным от ASCII, может отличаться.
Этот пост описывает это очень хорошо.
Вкратце: utf8_unicode_ci использует алгоритм сортировки Unicode, как определено в стандартах Unicode, тогда как utf8_general_ci - более простой порядок сортировки, что приводит к "менее точным" результатам сортировки.
utf8_unicode_ci
и представьте, что другой не существует.
См. руководство по mysql, Unicode Character Sets:
Для любого набора символов Юникода, операции, выполненные с использованием _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_unicode_ci
(это предпочтительный метод),
но если вы полностью заинтересованы в производительности - используйте utf8_general_ci
, но знайте, что он немного устарел.
Различия в показателях производительности очень незначительны.
Есть диаграммы для сортировки символов: http://collation-charts.org/mysql60/mysql604.utf8_general_ci.european.html и http://collation-charts.org/mysql60/mysql604.utf8_unicode_ci.european.html.
Для сохранения значений, таких как "é" и "e" в уникальном столбце, вы должны настроить его сопоставление на "ut8_bin", чтобы избежать дублирования ошибки.
Я не вижу на самом деле преимуществ использования utf8_unicode_ci в повседневном использовании.
utf8[mb4]_unicode_ci
, вам может понравитьсяutf8[mb4]_unicode_520_ci
еще больше.