Між utf8_general_ci
та utf8_unicode_ci
, чи є якісь відмінності щодо продуктивності?
utf8[mb4]_unicode_ci
, вам може сподобатися utf8[mb4]_unicode_520_ci
ще більше.
utf8mb4_0900_ai_ci
.
Між utf8_general_ci
та utf8_unicode_ci
, чи є якісь відмінності щодо продуктивності?
utf8[mb4]_unicode_ci
, вам може сподобатися utf8[mb4]_unicode_520_ci
ще більше.
utf8mb4_0900_ai_ci
.
Відповіді:
Ці два порівняння обидва для кодування символів UTF-8. Відмінності полягають у тому, як сортується та порівнюється текст.
Примітка. У MySQL потрібно використовувати, utf8mb4
а не використовувати utf8
. Конфузно utf8
- хибна реалізація UTF-8 з ранніх версій MySQL, яка залишається лише для зворотної сумісності. Фіксована версія отримала назву utf8mb4
.
Примітка: Новіші версії MySQL оновили правила сортування Unicode, доступні під такими іменами, як utf8mb4_0900_ai_ci
для еквівалентних правил, заснованих на Unicode 9.0 - і без еквівалентного _general
варіанту. Люди, які зараз це читають, ймовірно, повинні використовувати одне з цих нових порівнянь замість того _unicode
чи іншого _general
. Багато з того, що написано нижче, вже не викликає особливого інтересу, якщо ви можете замість цього використовувати одне з нових посилань.
Основні відмінності
utf8mb4_unicode_ci
ґрунтується на офіційних правилах Unicode для універсального сортування та порівняння, які точно сортують у широкому діапазоні мов.
utf8mb4_general_ci
це спрощений набір правил сортування, який має на меті зробити так само добре, як це може зробити, використовуючи безліч скорочень, призначених для підвищення швидкості. Це не дотримується правил Unicode і призведе до небажаного сортування чи порівняння в деяких ситуаціях, наприклад, при використанні певних мов чи символів.
На сучасних серверах це підвищення продуктивності буде майже несуттєвим. Він був розроблений в той час, коли сервери мали невелику частину продуктивності процесора сучасних комп'ютерів.
Переваги utf8mb4_unicode_ci
понад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
за винятком випадків, коли точне сортування буде досить важливим, щоб виправдати вартість продуктивності. Сьогодні ці витрати на продуктивність майже не зникли, і розробники ставляться до інтернаціоналізації більш серйозно.
Слід аргументувати, що якщо швидкість для вас важливіша, ніж точність, ви також можете взагалі не робити сортування. Тривіально зробити алгоритм швидше, якщо він вам не потрібен, щоб бути точним. Отже, utf8mb4_general_ci
це компроміс, який, мабуть, не потрібен з міркувань швидкості і, мабуть, також не підходить з міркувань точності.
Ще одне, що я додам, це те, що навіть якщо ви знаєте, що ваша програма підтримує лише англійську мову, можливо, все ж доведеться мати справу з іменами людей, які часто можуть містити символи, які використовуються іншими мовами, на яких так само важливо правильно сортувати. . Використання правил Unicode у всьому допомагає додати душевного спокою, що дуже розумні люди Unicode дуже наполегливо працювали, щоб сортування працювало належним чином.
Що означають деталі
По-перше, ci
це для нечутливого до випадку сортування та порівняння. Це означає, що він підходить для текстових даних, а регістр не важливий. Інші типи зіставлення є cs
(залежно від регістру) для текстових даних, коли важливий регістр, і bin
, коли кодування має відповідати, біт для бітів, який підходить для полів, які дійсно закодовані двійкові дані (включаючи, наприклад, База64). Впорядкування залежно від регістру призводить до деяких дивних результатів, а порівняння з урахуванням регістру може призвести до того, що дублікати значень відрізняються лише в регістрі букв, тому порівняння з урахуванням регістру випадає з користі для текстових даних - якщо випадок має значення для вас, то в іншому випадку ігнорування пунктуації і так далі, ймовірно, також є значним, і двійкове порівняння може бути більш доречним.
Далі, unicode
або general
посилається на конкретні правила сортування та порівняння - зокрема, спосіб нормалізації чи порівняння тексту. Є багато різних наборів правил для кодування символів utf8mb4, з unicode
і general
бути два , які намагаються добре працювати у всіх можливих мовах , а не один конкретний один. Різниці між цими двома наборами правил є предметом цієї відповіді. Зверніть увагу, що unicode
використовуються правила Unicode 4.0. Останні версії MySQL додають набори правил, unicode_520
використовуючи правила з Unicode 5.2, та 0900
(скидаючи частину "unicode_"), використовуючи правила з Unicode 9.0.
І нарешті, utf8mb4
звичайно, кодування символів, яке використовується всередині. У цій відповіді я говорю лише про кодування на основі Unicode.
utf8_general_ci
: вона просто не працює. Це повернення до поганих старих часів ASCII stooopeeedity з п'ятдесяти років тому. Невідмінна відповідність регістру Unicode неможливо здійснити без складання карти складок з UCD. Наприклад, "Σίσυφος" має три різні сигми в ньому; або як нижній регістр "TSCHüẞ" є "tschüβ", а верхній регістр "tschüβ" - "TSCHÜSS". Ви можете мати рацію, або ви можете бути швидкими. Тому ви повинні користуватися utf8_unicode_ci
, тому що якщо ви не піклуєтесь про правильність, то це неважливо, щоб зробити це нескінченно швидко.
"か" == "が"
або "ǽ" == "æ"
. Для сортування це має сенс, але може бути дивно, якщо вибирати через рівності або мати справу з унікальними індексами - bugs.mysql.com/bug.php?id=16526
utf8mb4
- єдиний правильний вибір . З utf8
вами застрягли деякі 3-байтові варіанти UTF8 лише для MySQL, про які тільки MySQL (і MariaDB) знають, що робити. Решта світу використовує UTF8, який може містити до 4 байт на символ . Розробники MySQL неправильно назвали кодування домашньою мовою, utf8
і щоб не порушити зворотну сумісність, тепер вони повинні посилатися на реальний UTF8 як utf8mb4
.
Мені хотілося знати, в чому полягає різниця в роботі між використанням 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_unicode_ci
.
Я називав кожну збережену процедуру 5 разів за кожне порівняння (5 разів для utf8_general_ci
та 5 разів для utf8_unicode_ci
), а потім обчислював середні значення.
Мої результати такі:
benchmark_simple_select()
utf8_general_ci
: 9957 мс 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_general_ci
просто занадто мінімальне, щоб його варто використовувати.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
генерує лише ASCII, і ніякі символи Unicode не обробляються алгоритмами порівнянь. 2) Description = 'test' COLLATE ...
і Description LIKE 'test%' COLLATE ...
обробляти лише один рядок ("тест") під час виконання, чи не так? 3) У реальних додатках стовпці, що використовуються для впорядкування, ймовірно, будуть проіндексовані, а швидкість індексації у різних зіставленнях з реальним текстом, що не належить до ASCII, може відрізнятися.
Цей пост дуже добре описує це.
Якщо коротко: utf8_unicode_ci використовує алгоритм зібрання Unicode, як визначено у стандартах Unicode, тоді як utf8_general_ci - більш простий порядок сортування, що призводить до "менш точних" результатів сортування.
utf8_unicode_ci
і робіть вигляд, що іншого не існує.
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 буде швидшим, тому що обчислень буде менше.
utf8_unicode_ci
і робите вигляд, що помилкова версія не існує.
0
а 1
не бул. :) Вибір геопотоків у обмежувальному полі - це наближення "точок поблизу", що не так добре, як обчислення відстані між точкою та опорною точкою та фільтрація по цьому. Але обидва - це наближення, і фактично повна коректність здебільшого не досяжна. Дивіться парадокс узбережжя та IEEE 754
1/3
Коротко кажучи:
Якщо вам потрібен кращий порядок сортування - використовуйте utf8_unicode_ci
(це кращий метод),
але якщо вас дуже цікавить продуктивність - використовуйте utf8_general_ci
, але знайте, що вона трохи застаріла.
Відмінності щодо продуктивності дуже незначні.
Як ми можемо прочитати тут ( Пітер Гулутзан ), існує різниця в сортуванні / порівнянні польської літери "Ł" (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
. Ніхто з цього кодування не є кращим чи гіршим - це залежить від ваших потреб.
Існує дві великі різниці в сортуванні та відповідності символів:
Сортування :
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
.
Повний список відповідностей для кожної колокації можна знайти тут .
Відповідно до цієї публікації, на MySQL 5.7 є значно велика користь при використанні utf8mb4_general_ci замість utf8mb4_unicode_ci: https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mysql-вистава /