Між 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-вистава /