Какая разница между utf8_general_ci и utf8_unicode_ci

Между utf8_general_ci и utf8_unicode_ci существуют ли различия в производительности?

Ответ 1

Эти два сопоставления предназначены для кодировки символов UTF-8. Различия заключаются в том, как текст сортируется и сравнивается.

Примечание. Начиная с MySQL 5.5.3, вы должны использовать utf8mb4, а не utf8. Они оба ссылаются на кодировку UTF-8, но более старый utf8 имел специфичное для MySQL ограничение, запрещающее использование символов с номерами выше 0xFFFD.

Ключевые отличия

  • utf8mb4_unicode_ci основан на официальных правилах Unicode для универсальной сортировки и сравнения, которая точно сортирует по широкому спектру языков.

  • utf8mb4_general_ci - это упрощенный набор правил сортировки, цель которого - сделать все возможное, используя множество ярлыков, предназначенных для повышения скорости. Он не соответствует правилам Юникода и может привести к нежелательной сортировке или сравнению в некоторых ситуациях, например при использовании определенных языков или символов.

    На современных серверах это повышение производительности будет практически незначительным. Он был разработан в то время, когда серверы имели небольшую долю производительности ЦП современных компьютеров.

Примечание: в настоящее время существует обновленная версия 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 для сортировки и сравнения, использует довольно сложный алгоритм для правильной сортировки в широком диапазоне языков и при использовании широкого диапазона специальных символов. Эти правила должны учитывать языковые соглашения; не каждый сортирует своих персонажей в том, что мы назвали бы "алфавитным порядком".

Что касается латиницы (то есть "европейских") языков, между сортировкой Unicode и упрощенной сортировкой utf8mb4_general_ci в MySQL нет большой разницы, но есть еще несколько отличий:

  • Например, параметры сортировки Unicode сортируют "ß", например, "ss", и "Œ", например "OE", как обычно хотят люди, использующие эти символы, тогда как utf8mb4_general_ci сортирует их как одиночные символы (предположительно, как "s" и "e"). "соответственно).

  • Некоторые символы Юникода определены как игнорируемые, что означает, что они не должны учитываться в порядке сортировки, и сравнение должно перейти к следующему символу. utf8mb4_unicode_ci обрабатывает их правильно.

В нелатинских языках, таких как азиатские языки или языки с разными алфавитами, может быть намного больше различий между сортировкой Unicode и упрощенной сортировкой 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-кодировках.

Ответ 2

Я хотел знать, в чем разница в производительности между использованием 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 с 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_general_ci и utf8_unicode_ci.

Я вызывал каждую хранимую процедуру 5 раз для каждого сопоставления (5 раз для utf8_general_ci и 5 раз для utf8_unicode_ci), а затем вычислял средние значения.

Мои результаты:

benchmark_simple_select()

  • с utf8_general_ci: utf8_general_ci мс
  • с 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%.

Ответ 3

Этот пост описывает это очень хорошо.

Вкратце: utf8_unicode_ci использует алгоритм сортировки Unicode, как определено в стандартах Unicode, тогда как utf8_general_ci - более простой порядок сортировки, что приводит к "менее точным" результатам сортировки.

Ответ 4

См. Руководство по 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 будет быстрее, потому что требуется меньше вычислений.

Ответ 5

Вкратце:

Если вам нужен лучший порядок сортировки - используйте utf8_unicode_ci (это предпочтительный метод),

но если вы крайне заинтересованы в производительности - используйте utf8_general_ci, но знайте, что она немного устарела.

Различия с точки зрения производительности очень незначительны.

Ответ 6

Некоторые детали (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 Ни одна из этих кодировок не является лучше или хуже - это зависит от ваших потребностей.

Ответ 8

Есть диаграммы для сортировки символов: 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 в повседневном использовании.