Як працює порівняння з урахуванням регістру?


19

Тип зіставлення за замовчуванням у SQL Server дозволяє індексувати рядки, нечутливі до регістру, однак випадок даних зберігається. Як це насправді працює? Я шукаю фактичні гайки та болти, шматочки та байти чи хороший ресурс, який детально пояснює це.

create table casetest (fruitnames nvarchar(50) not null);
create unique index IX_fruitnames on casetest(fruitnames);

insert into casetest values ('apples');
insert into casetest values ('Pears');
-- this insert fails
insert into casetest values ('pears');

-- this yields 'Pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

update casetest set fruitnames = 'pears' where fruitnames = 'pEArs'

-- this yields 'pears' as a result
select * from casetest (forceseek) where fruitnames = 'PEARS'

Питання про зібрання на сервері SQL, яких ви були занадто сором'язливими для Роберта Шелдона, розповідає про те, як використовувати зіставлення. Він не висвітлює, як працює співставлення. Мене цікавить, як індекс можна ефективно створювати / запитувати, не піклуючись про справу, одночасно зберігаючи дані справи.


1
Ви можете ефективно запитувати (наприклад, використовуючи пошук за допомогою індексу) рядків, нечутливих до регістру, щодо чутливого до регістру поля, але це трохи дратує .
Джон Ейсбренер

cocogorilla: дивіться примітку №1, яку я щойно додав до кінця своєї відповіді щодо: "за замовчуванням".
Соломон Руцький

Відповіді:


26

індексування до рядків, нечутливих до регістру, але справа даних зберігається. Як це насправді працює?

Це насправді не поведінка, характерна для SQL Server, це лише те, як ці речі працюють взагалі.

Отже, дані - це дані. Якщо ви конкретно говорите про індекс, дані потрібно зберігати, як інакше, це вимагатиме кожного разу шукати в головній таблиці, щоб отримати фактичне значення, і немає можливості охоплювати індекс (у принаймні, не для типів рядків).

Дані в таблиці / кластерному індексі або некластеризованому індексі не містять ніякої інформації про порівняння / сортування. Це просто дані. Порівнювання (правила локалізації / культури та чутливості) - це лише метадані, приєднані до стовпця і використовуються при виклику операції сортування (якщо тільки це не перекритоCOLLATEпункт), який би включав створення / відновлення індексу. Правила, визначені небінарним зіставленням, використовуються для генерації ключів сортування, які є двійковими представленнями рядка (сортування ключів є непотрібним у двійкових зіставленнях). Ці бінарні уявлення містять усі правила локалізації / культури та вибрані чутливості. Клавіші сортування використовуються для розміщення записів у належному порядку, але самі не зберігаються в індексі чи таблиці. Вони не зберігаються (принаймні, я не бачив цих значень в індексі, і мені сказали, що вони не зберігаються), оскільки:

  1. Вони справді не потрібні для сортування, оскільки вони просто будуть у тому ж порядку, що й рядки в таблиці чи індекс. Але фізичний порядок індексу - це лише сортування, а не порівняння.
  2. Хоча зберігання їх може зробити порівняння швидшими, це також зробить індекс більшим, оскільки мінімальний розмір для одного символу становить 5 байт, і це просто "накладні витрати" (структури сортування ключів). Більшість символів - 2 байти, плюс 1 байт, якщо є наголос, плюс 1 байт, якщо це великий регістр. Наприклад, "e" - це 7-байтний ключ, "E" і "é" - це 8 байт, а "É" - 9-байтний ключ. Отже, не варто зберігати їх у підсумку.

Існує два типи порівнювань: SQL Server та Windows.

SQL Server

Параметри сортування SQL Server (ті , з іменами , які починаються часткою з SQL_) є старі, попередньо SQL Server 2000 спосіб сортування / порівняння (навіть якщо SQL_Latin1_General_CP1_CI_ASце все ще установки по замовчуванням на американському англійською операційки, досить сумно). У цій старшій, спрощеній моделі, яка не використовується Unicode, кожній комбінації мови, кодової сторінки та різної чутливості надається статичне відображення кожного з символів на цій сторінці коду. Кожному символу присвоюється значення (тобто вага сортування) для позначення того, як воно зрівняється з іншими. Порівняння в цій моделі, схоже, виконують операцію з двома проходами:

  1. По-перше, він видаляє всі наголоси (такі, що "  ü  " стає "  u  "), розширює символи типу "  Æ  " на "  A  " і "  E  ", потім робить початковий сортування, щоб слова були в природному порядку (як би ви очікуємо знайти їх у словнику).
  2. Потім, він переходить символ за символом, щоб визначити рівність на основі цих базових значень для кожного символу. Ця друга частина - те, що описує Мустаччо у своїй відповіді .

Єдині чутливості, які можна регулювати в цих зіставленнях, є: "регістр" та "наголос" ("ширина", "тип кана" та "селектор варіації" недоступні). Крім того, жодне з цих зіставлень не підтримує додаткових символів (що має сенс, оскільки вони є специфічними для Unicode, і ці зіставлення застосовуються лише до даних, що не стосуються Unicode).

Цей підхід застосовується лише до даних, що не стосуються Unicode VARCHAR. Кожна унікальна комбінація мови, кодової сторінки, чутливості до регістру та чутливості до акценту має специфічний "ідентифікатор сортування", який ви можете побачити у наступному прикладі:

SELECT COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CI_AS', 'SortID'), -- 52
       COLLATIONPROPERTY(N'SQL_Latin1_General_CP1_CS_AS', 'SortID'), -- 51
       COLLATIONPROPERTY(N'Latin1_General_100_CI_AS',     'SortID'); --  0

Єдина відмінність між першими двома порівняннями - це чутливість до регістру. Третє порівняння - це зіставлення Windows, і тому не має таблиці статичного відображення.

Крім того, ці зіставлення повинні сортуватись та порівнюватись швидше, ніж порівняння Windows, оскільки вони прості шукають символи для сортування ваги. Однак ці порівняння також набагато менш функціональні, і їх взагалі слід уникати, якщо це можливо.

Windows

Порівняння Windows (ті, у кого імена не починаються SQL_) - це новіший (починаючи з SQL Server 2000) спосіб сортування / порівняння. У цій більш новій, складній моделі Unicode кожній комбінації локалі, кодової сторінки та різної чутливості не надається статичне відображення. З одного боку, у цій моделі немає кодових сторінок. Ця модель присвоює значення сортування за замовчуванням кожному символу, і тоді кожна локаль / культура може повторно призначити значення сортування будь-якій кількості символів. Це дозволяє різним культурам використовувати одні й ті самі символи по-різному. Це може вплинути на можливість сортування декількох мов природним чином за допомогою одного і того ж зіставлення, якщо вони не використовують однакові символи (і якщо одному з них не потрібно повторно призначати будь-які значення та просто використовувати за замовчуванням).

Значення сортування в цій моделі не є одиничними значеннями. Вони являють собою масив значень, які присвоюють відносні ваги базовій літері, будь-якій діакритиці (тобто наголоси), кожуху тощо. Якщо зіставлення залежить від регістру, то використовується "регістр" цього масиву, інакше він ігнорується ( отже, нечутливий). Якщо зіставлення чутливе до акцентів, тоді використовується "діакритична" частина масиву, інакше вона ігнорується (отже, нечутлива).

Порівняння в цій моделі є багатопрохідною операцією:

  1. По-перше, рядок нормалізується так, що різні способи подання одного і того ж символу зрівняються. Наприклад, " ü " може бути одним символом / кодовою точкою (U + 00FC). Крім того, можна об'єднати , не підкреслений « ˙U » (U + 0075) з Об'єднуючи трьома « ··· » (U + 0308) , щоб отримати: « ü », який не тільки виглядає так само , коли виявляється (якщо немає проблем з ваш шрифт), але також вважається таким же, як і версія одного символу (U + 00FC), за винятком випадків, коли використовується двійкове порівняння (яке порівнює байти замість символів). Нормалізація розбиває один символ на різні фрагменти, що включає розширення для символів типу "  Æ  " (як зазначено вище для порівнянь на SQL Server).
  2. Операція порівняння в цій моделі має характер за символом для кожної чутливості . Клавіші сортування рядків визначаються шляхом застосування відповідних елементів масиву зіставлення кожного символу на основі яких чутливості "чутливі". Ключові значення сортування впорядковуються за всіма первинними чутливості кожного символу (базовим символом), за ними слідують усі вторинні чутливості (діакритична вага), а потім вага випадку кожного символу тощо.
  3. Сортування проводиться на основі розрахованих клавіш сортування. Коли кожна чутливість згрупована разом, ви можете отримати інший порядок сортування, ніж ви б при еквівалентному зіставленні SQL Server, коли порівнюєте рядки з декількох символів, а також наголоси, а порівняння чутливе до акцентів (і тим більше, якщо порівняння є також залежно від регістру).

Для отримання більш докладної інформації по цій сортуванні, я в кінцевому підсумку опублікувати пост , який показує , що - то ключові цінності, як вони розраховуються, відмінність між SQL Server і Windows , сортуванням і т.д. Але на даний момент, будь ласка , см моєї відповіді на: Accent Sensitive Sort ( зауважте, що інша відповідь на це питання є хорошим поясненням офіційного алгоритму Unicode, але натомість SQL Server використовує користувальницький, хоча й аналогічний, алгоритм і навіть власну таблицю ваги).

Усі чутливості можуть бути відрегульовані в цих зіставленнях: "регістр", "акцент", "ширина", "тип кана" та "селектор варіацій" (починаючи з SQL Server 2017, і лише для японських посилань). Також деякі з цих зіставлень (коли вони використовуються з даними Unicode) підтримують додаткові символи (починаючи з SQL Server 2012). Цей підхід застосовується як до даних, так NVARCHAR і до VARCHAR даних (навіть даних, що не стосуються Unicode). Він застосовується до даних, що не стосуються Unicode VARCHAR, спочатку перетворюючи значення в Unicode внутрішньо, а потім застосовуючи правила сортування / порівняння.


Будь ласка, запиши:

  1. Не існує універсального порівняння за замовчуванням для SQL Server. Існує налаштування за замовчуванням, яке відрізняється залежно від поточного налаштування мови / мови ОС на момент встановлення (що, на жаль, SQL_Latin1_General_CP1_CI_ASдля американських англійських систем, тому, будь ласка, проголосуйте за цю пропозицію ). Це можна змінити під час встановлення. Це зіставлення на рівні примірника потім встановлює зіставлення для [model]БД, що є шаблоном, використовуваним при створенні нових БД, але порівняння може бути змінено при виконанні CREATE DATABASE, вказавши COLLATEпункт. Це порівняння на рівні бази даних використовується для змінних та рядкових літералів, а також за замовчуванням для нових (та змінених!) Стовпців, коли COLLATEпункт не вказано (що стосується прикладу коду у питанні).
  2. Для отримання додаткової інформації про зібрання / кодування / Unicode відвідайте: Інформація про зібрання

5

Зазвичай це реалізується за допомогою таблиць зіставлення, які присвоюють певний бал кожному символу. У процедурі сортування є порівняльник, який використовує відповідну таблицю, чи за замовчуванням, чи явно вказану, для порівняння рядків, символів за символами, використовуючи їх оцінки порівняння. Наприклад, якщо певна таблиця порівняння призначає бал від 1 до "a" і 201 до "A", а нижчий бал у цій конкретній реалізації означає більш високий пріоритет, то "a" буде сортуванням перед "A". Інша таблиця може присвоїти зворотні бали: 201 до "a" і 1 до "A", а порядок сортування буде згодом зворотним. Ще одна таблиця може присвоїти однакові бали "a", "A", "Á" та "Å", що призведе до порівняння та сортування, нечутливого до випадків та акцентів.

Аналогічно, такий порівняльник на основі таблиці зіставлення використовується при порівнянні індексного ключа зі значенням, поданим у предикаті.


1
Просто FYI: ця інформація є правильною лише з точки зору використання порівнювань SQL Server (тобто тих, у яких імена починаються з SQL_) при використанні VARCHARданих. Це не зовсім вірно для NVARCHARданих або VARCHARданих, коли використовується зіставлення Windows (імена не починаються з SQL_).
Соломон Руцький
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.