Коли `nvarchar / nchar` буде використовуватися з SQL Server 2019?


11

У SQL Server 2019 Microsoft вводить підтримку UTF-8 для CHARі VARCHARтипів даних і каже:

Ця функція може забезпечити значну економію пам’яті, залежно від набору символів, що використовуються. Наприклад, зміна існуючого типу даних стовпців з рядками ASCII з NCHAR (10) на CHAR (10) за допомогою зіставлення з підтримкою UTF-8, означає, що майже на 50% зменшуються вимоги до зберігання. Це зменшення пояснюється тим, що для зберігання NCHAR (10) потрібно 22 байти для зберігання, тоді як CHAR (10) вимагає 12 байт для тієї ж строки Unicode.

Здається, UTF-8 підтримує кожен сценарій, тому в основному ми можемо почати зберігати дані Unicode у varcharта charстовпцях. І як сказано в документації, це може зменшити розмір таблиць та індексів, і звідти ми можемо отримати ще кращу продуктивність, оскільки читається менший обсяг даних.

Мені цікаво, чи означає це, що ми можемо перестати використовувати nvarcharі ncharстовпці, які реалізують UTF-16?

Чи може хтось вказати на сценарій та причину, щоб не використовувати типи даних char із UTFкодуванням і продовжувати використовувати n-символи?


Чому б ви не протестували його і не звітували? Також повідомте нам, скільки зусиль ви витратили, щоб перетворити з nvarchar у varchar - скільки часу зайняли таблиці змін і скільки часу ви витратили на тестування, і з якими проблемами ви зіткнулися.
Colin 't Hart

@ Colin'tHart Якщо немає відомих проблем або міркувань, я планую перенести дані, оскільки я вважаю, що читання менше даних призведе до кращої роботи системи. Щодо конверсії - це потребуватиме певного часу, особливо, якщо у вас є індекси із заданим стовпцем - їх потрібно відновлювати, але я вважаю, що це добре окупиться. Звичайно, я скоро перевіряю на ефективність, просто шукаю будь-які проблеми, які зроблять міграцію непотрібною.
gotqn

Зауважте, що SQL Server підтримує стиснення Unicode для стовпців NVarchar при використанні стиснення PAGE або ROW. docs.microsoft.com/en-us/sql/relational-databases/…
Девід Браун - Microsoft

1
Варто зазначити, що хоча UTF-8 може економити місце, якщо ви зберігаєте "схожі на ASCII дані", це не є стисненням саме по собі, і не слід помилятися як таке. Наприклад, якщо ви зберігаєте в основному китайські імена в базі даних, вам буде гірше використовувати CHARтипи UTF-8, ніж типи Unicode (з або без стиснення, оскільки в кінцевому рахунку дані повинні бути нестисненими, щоб обробити). Також слід врахувати, що рідний тип рядка Windows - це Unicode, тому рядки UTF-8 часто потрібно декодувати. Задіяні компроміси означають, що Nскоро не вдасться вийти з виду.
Єроен Мостерт

1
"Убивчий додаток №1" для UTF-8 CHAR, ймовірно, є SQL Server в Linux, якщо двигун отримує вбудовану підтримку для обробки рядків безпосередньо як UTF-8 - тут UTF-8 є "рідним" набором символів (більш-менш) і збереження рядків навколо UTF-16 є менш ефективною альтернативою. Звичайно, це також не завадить використовувати його в Windows там, де ви вже користуєтесь CHAR, оскільки порівняння, що обмежують символи, які можна зберігати, ніколи не були привабливими.
Jeroen Mostert

Відповіді:


6

це може зменшити розмір таблиць та індексів (наголос додано)

Зменшення розміру можливо тільки , якщо більшість персонажів, по суті [space], 0 - 9, A - Z, a - z, і деякі основні знаки пунктуації. Поза певним набором символів (у практичному використанні, стандартні значення ASCII 32 - 126) ви будете в кращому випадку рівними NVARCHAR/ UTF-16, або в багатьох випадках більшими.

Я планую перенести дані, оскільки я вважаю, що читання менших даних призведе до кращої роботи системи.

Будь обережний. UTF-8 - не чарівний перемикач "виправити все". За інших рівних умов, так, менше читання покращує продуктивність. Але тут "всі інші речі" не рівні. Навіть при зберіганні лише стандартних символів ASCII (це означає, що всі символи мають 1 байт, тому NVARCHARдля використання UTF-8 потрібна половина місця в порівнянні з зберіганням ). Я вважаю, що проблема пов’язана з тим, що UTF-8 є кодуванням змінної довжини, а це означає, що кожен байт повинен інтерпретуватися так, як він читається, щоб знати, чи є повноцінним символом або чи наступний байт є його частиною. Це означає, що всі рядкові операції потрібно починати на початку та продовжувати байт-байт. З іншої сторони,NVARCHAR / UTF-16 - це завжди 2 байти (навіть додаткові символи складаються з двох 2-байтних точок коду), тому все можна прочитати в 2-байтових фрагментах.

У моєму тестуванні, навіть із лише стандартними символами ASCII, зберігання даних як UTF-8 не забезпечило економії минулого часу, але, безумовно, гірше для процесорного часу. І це було без стиснення даних, тому принаймні було менше використано дискового простору. Але, використовуючи стиснення, місця, необхідного для UTF-8, було лише на 1% - на 1,5% менше. Таким чином, економія простору ще не перевищує час процесора для UTF-8.

Речі ускладнюються при використанні, NVARCHAR(MAX)оскільки Unicode Compression не працює з цим типом даних, навіть якщо значення є досить малим, щоб зберігатись у рядку. Але, якщо дані досить малі, вони все-таки повинні скористатися стисненням рядків або сторінок (у такому випадку вони фактично стають швидшими, ніж UTF-8). Однак дані, що не входять у рядок, не можуть використовувати жодне стиснення. Тим не менш, перетворення таблиці на індекс кластерних стовпців значно зменшує розмір NVARCHAR(MAX)(навіть якщо він все-таки трохи більший, ніж UTF-8 при використанні індексу кластерних стовпців).

Хтось може вказати на сценарій та причину, щоб не використовувати типи даних char із кодуванням UTF

Безумовно. Насправді я не знаходжу переконливої ​​причини використовувати його в більшості випадків. Єдиний сценарій, який справді виграє від UTF-8, це:

  1. Дані переважно стандартні ASCII (значення 0 - 127)
  2. Він повинен бути Unicode, тому що, можливо, потрібно буде зберігати ширший спектр символів, ніж це доступно на будь-якій 8-бітній кодовій сторінці (тобто VARCHAR)
  3. Більшість даних зберігаються поза рядками (тому стиснення сторінки навіть не працює)
  4. У вас достатньо даних, які вам потрібні / хочете зменшити розмір з причин, що не відповідають запитам (наприклад, зменшити розмір резервної копії, скоротити час, необхідний для резервного копіювання / відновлення тощо)
  5. Ви не можете використовувати індекс кластерних стовпців (можливо, використання таблиці в цьому випадку погіршує продуктивність?)

Моє тестування показує, що майже у всіх випадках NVARCHAR був швидшим, особливо коли було більше даних. Насправді, для 21k рядків із середнім значенням 5k в рядку потрібно 165 MB для UTF-8 та 236 MB для NVARCHARнестиснених. І тим не менш, NVARCHAR2 рази швидше за минулий час і принаймні 2 рази швидше (іноді більше) за час процесора. Тим не менш, це займало 71 Мб більше на диску.

Крім цього, я все одно не рекомендую використовувати UTF-8, принаймні, як CTP 2, через різні помилки, які я знайшов у цій функції.

Для детального аналізу цієї нової функції, включаючи пояснення відмінностей між UTF-16 та UTF-8, та перелік цих помилок, будь ласка, дивіться мій пост:

Рідна підтримка UTF-8 у SQL Server 2019: рятівник чи помилковий пророк?


12

Підтримка UTF-8 надає новий набір варіантів. Потенційна економія простору (без стискання рядків чи сторінок ) - це одне врахування, але вибір типу та кодування, мабуть, повинен здійснюватися насамперед на основі фактичних вимог порівняння, сортування, імпорту даних та експорту .

Можливо, вам доведеться змінити більше, ніж ви думаєте, оскільки, наприклад, nchar(1)тип забезпечує два байти сховища. Цього достатньо для зберігання будь-якого символу в BMP (кодові точки 000000 до 00FFFF). Деякі символи в цьому діапазоні будуть закодовані лише в 1 байті в UTF-8, а інші потребують 2 або навіть 3 байти (див. Цю порівняльну діаграму для отримання більш детальної інформації). Таким чином, потрібно охопити той самий набір символів у UTF-8 char(3).

Наприклад:

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 char(1) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

дає звичну помилку:

Msg 8152, рівень 16, стан 30, рядок xxx
Рядок або двійкові дані будуть усічені.

Або якщо активний прапор трасування 460:

Msg 2628, рівень 16, стан 1, рядок xxx
Рядок або двійкові дані будуть усічені в таблиці '@T', стовпчик 'UTF8'. Усечене значення: ''.

Розширення стовпця UTF8 до char(2)або varchar(2)усунення помилки для NCHAR(911):

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 varchar(2) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

Однак, якби це було, наприклад NCHAR(8364), вам потрібно буде розгорнути стовпчик далі, до char(3)або varchar(3).

Зауважте також, що всі зібрання UTF-8 використовують додаткові символи, тому з реплікацією не працюватимуть .

Окрім нічого іншого, підтримка UTF-8 наразі є лише в попередньому перегляді, тому не доступна для використання у виробництві.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.