Jak działa sortowanie bez rozróżniania wielkości liter?

19

Domyślny typ sortowania w SQL Server pozwala na indeksowanie ciągów znaków bez rozróżniania wielkości liter, ale wielkość danych jest zachowywana. Jak to faktycznie działa? Szukam rzeczywistych nakrętek i śrub, bitów i bajtów lub dobrego zasobu, który szczegółowo to wyjaśnia.

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'

Pytania dotyczące zestawień SQL Server Byliście zbyt nieśmiali, by zadać je Robert Sheldon, omawia sposób korzystania z zestawiania. Nie obejmuje działania sortowania. Interesuje mnie, w jaki sposób można efektywnie utworzyć / zapytać o indeks, nie troszcząc się o wielkość liter przy jednoczesnym przechowywaniu danych o wielkości liter.

cocogorilla
źródło
1
Możesz efektywnie wyszukiwać (np. Wykorzystując wyszukiwanie indeksu) ciągi bez rozróżniania wielkości liter względem pola z rozróżnianiem wielkości liter, ale jest to trochę denerwujące .
John Eisbrener
cocogorilla: proszę zobaczyć uwagę nr 1, którą właśnie dodałem na końcu mojej odpowiedzi, dotyczącą: „domyślnego” sortowania.
Solomon Rutzky

Odpowiedzi:

26

indeksowanie ciągów znaków bez rozróżniania wielkości liter, ale przypadek danych jest utrwalany. Jak to faktycznie działa?

W rzeczywistości nie jest to zachowanie specyficzne dla SQL Server, to po prostu, jak te rzeczy działają w ogóle.

Dane są więc danymi. Jeśli mówimy konkretnie o indeksie, dane muszą być przechowywane, ponieważ w innym przypadku wymagałoby to każdorazowego sprawdzenia w głównej tabeli, aby uzyskać rzeczywistą wartość, i nie byłoby możliwości zastosowania indeksu obejmującego (w najmniej dla typów ciągów).

Dane, zarówno w indeksie tabel / indeks klastrowy, jak i indeks nieklastrowany, nie zawierają żadnych informacji o sortowaniu / sortowaniu. To po prostu dane. Sortowanie (reguły regionalne / kultura i wrażliwości) to tylko metadane dołączone do kolumny i używane, gdy wywoływana jest operacja sortowania (chyba że zostanie zastąpiona przezCOLLATEklauzula), która obejmowałaby utworzenie / przebudowę indeksu. Reguły zdefiniowane przez niebinarne zestawienie są używane do generowania kluczy sortowania, które są binarnymi reprezentacjami łańcucha (klucze sortowania nie są potrzebne w zestawieniach binarnych). Te reprezentacje binarne uwzględniają wszystkie reguły regionalne / kulturowe i wybrane wrażliwości. Klawisze sortowania służą do umieszczania rekordów we właściwej kolejności, ale same nie są przechowywane w indeksie lub tabeli. Nie są przechowywane (przynajmniej nie widziałem tych wartości w indeksie i powiedziano mi, że nie są przechowywane), ponieważ:

  1. Nie są tak naprawdę potrzebne do sortowania, ponieważ i tak byłyby w tej samej kolejności co wiersze w tabeli lub indeksie. Ale fizyczna kolejność indeksu to tylko sortowanie, a nie porównywanie.
  2. Przechowywanie ich może przyspieszyć porównania , ale zwiększy także indeks, ponieważ minimalny rozmiar pojedynczego znaku wynosi 5 bajtów, a to po prostu „narzut” (struktury klucza sortowania). Większość znaków ma po 2 bajty plus 1 bajt, jeśli występuje akcent, oraz 1 bajt, jeśli jest to duża litera. Na przykład „e” to 7-bajtowy klucz, „E” i „é” to 8 bajtów, a „É” to 9-bajtowy klucz. Dlatego nie warto ich przechowywać na końcu.

Istnieją dwa rodzaje zestawień: SQL Server i Windows.

SQL Server

SQL_Sortowania SQL Server (te o nazwach rozpoczynających się od ) są starszym sposobem sortowania / porównywania sprzed SQL Server 2000 (choć niestety nadalSQL_Latin1_General_CP1_CI_AS jest to domyślna instalacja w amerykańskich systemach operacyjnych w języku angielskim). W tym starszym, uproszczonym modelu nieobsługującym kodu Unicode każda kombinacja ustawień regionalnych, strony kodowej i różnych wrażliwości ma statyczne mapowanie każdego ze znaków na tej stronie kodowej. Każdemu znakowi przypisuje się wartość (tj. Wagę sortowania), aby wskazać, jak jest on równy z innymi. Porównania w tym modelu wydają się wykonywać operację dwuprzebiegową:

  1. Najpierw usuwa wszystkie akcenty (takie, że „  ü  ” staje się „  u  ”), rozwija znaki takie jak „  Æ  ” do „  A  ” i „  E  ”, a następnie sortuje początkowo, aby słowa były w naturalnej kolejności (jak byś spodziewaj się, że znajdziesz je w słowniku).
  2. Następnie przechodzi znak po znaku, aby ustalić równość na podstawie tych wartości leżących u podstaw każdego znaku. Ta druga część jest tym, co Mustaccio opisuje w swojej odpowiedzi .

Jedynymi czułościami, które można regulować w tych zestawieniach, są: „wielkość liter” i „akcent” („szerokość”, „typ kana” i „selektor wariacji” nie są dostępne). Ponadto żadne z tych zestawień nie obsługuje znaków uzupełniających (co ma sens, ponieważ są one specyficzne dla Unicode, a te zestawienia dotyczą tylko danych innych niż Unicode).

To podejście dotyczy tylko danych nieobsługujących kodu Unicode VARCHAR. Każda unikalna kombinacja ustawień regionalnych, strony kodowej, rozróżniania wielkości liter i rozróżniania akcentów ma określony „identyfikator sortowania”, który można zobaczyć w następującym przykładzie:

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

Jedyną różnicą między pierwszymi dwoma zestawieniami jest rozróżnianie wielkości liter. Trzecie sortowanie to sortowanie w systemie Windows, a zatem nie ma statycznej tabeli mapowania.

Ponadto te sortowania powinny być sortowane i porównywane szybciej niż sortowania w systemie Windows, ponieważ są prostymi funkcjami wyszukiwania znaków do sortowania według wagi. Jednak te zestawienia są również znacznie mniej funkcjonalne i należy ich unikać, jeśli to w ogóle możliwe.

Windows

Sortowania w systemie Windows (te o nazwach, które nie zaczynają się od SQL_) są nowszym (począwszy od SQL Server 2000) sposobem sortowania / porównywania. W tym nowszym, złożonym modelu Unicode każda kombinacja ustawień narodowych, strony kodowej i różnych wrażliwości nie ma przypisania statycznego. Po pierwsze, w tym modelu nie ma stron kodowych. Ten model przypisuje domyślną wartość sortowania do każdego znaku, a następnie każde ustawienie regionalne / kultura może ponownie przypisać wartości sortowania do dowolnej liczby znaków. Pozwala to wielu kulturom używać tych samych znaków na różne sposoby. Ma to wpływ na umożliwienie naturalnego sortowania wielu języków przy użyciu tego samego sortowania, jeśli nie używają one tych samych znaków (i jeśli jeden z nich nie musi ponownie przypisywać żadnych wartości i może po prostu użyć domyślnych).

Wartości sortowania w tym modelu nie są pojedynczymi wartościami. Są to tablice wartości, które przypisują względne wagi do litery podstawowej, wszelkich znaków diakrytycznych (tj. Akcentów), obudowy itp. Jeśli w sortowaniu rozróżniana jest wielkość liter, wówczas używana jest część „wielkość liter” w tej tablicy, w przeciwnym razie zostanie zignorowana stąd niewrażliwy). Jeśli zestawienie jest wrażliwe na akcent, wówczas używana jest „diakrytyczna” część tablicy, w przeciwnym razie jest ignorowana (stąd niewrażliwa).

Porównania w tym modelu są operacją wieloprzebiegową:

  1. Po pierwsze, łańcuch jest znormalizowany, aby zrównać się różne sposoby reprezentowania tego samego znaku. Na przykład „ ü ” może być pojedynczym znakiem / punktem kodowym (U + 00FC). Możesz także połączyć nieakcentowane „ u ” (U + 0075) z łączną diaeresisą „ ̈ ” (U + 0308), aby uzyskać: „ ü ”, który nie tylko wygląda tak samo po renderowaniu (chyba że występuje problem z twoja czcionka), ale jest również uważany za taki sam jak wersja jednoznakowa (U + 00FC), chyba że używasz sortowania binarnego (który porównuje bajty zamiast znaków). Normalizacja dzieli pojedynczy znak na różne części, w tym rozszerzenia dla znaków takich jak „  Æ  ” (jak wspomniano powyżej dla zestawień SQL Server).
  2. Operacja porównania w tym modelu przebiega znak po znaku na każdą czułość . Klucze sortowania dla łańcuchów są określane przez zastosowanie odpowiednich elementów tablicy sortowania wartości każdego znaku, na podstawie której „wrażliwość” jest wrażliwa. Kluczowe wartości sortowania są uporządkowane według wszystkich pierwotnych wartości czułości każdego znaku (znak podstawowy), po których następują wszystkie wartości dodatkowej czułości (waga diakrytyczna), a następnie waga wielkości liter każdego znaku i tak dalej.
  3. Sortowanie odbywa się na podstawie obliczonych kluczy sortowania. Przy każdej pogrupowanej czułości można uzyskać inną kolejność sortowania niż w przypadku równoważnego sortowania programu SQL Server podczas porównywania ciągów wielu znaków i zaangażowanych akcentów, a sortowanie jest wrażliwe na akcent (a tym bardziej, jeśli zestawienie jest rozróżniana jest również wielkość liter).

Aby uzyskać więcej informacji na temat tego sortowania, ostatecznie opublikuję post, który pokazuje kluczowe wartości sortowania, sposób ich obliczania, różnice między SQL Server i zestawieniami Windows itp. Ale na razie zapoznaj się z moją odpowiedzią na: Sortowanie wrażliwe na akcent ( należy pamiętać, że inna odpowiedź na to pytanie jest dobrym wyjaśnieniem oficjalnego algorytmu Unicode, ale zamiast tego SQL Server używa niestandardowego, choć podobnego algorytmu, a nawet niestandardowej tabeli wag).

Wszystkie wrażliwości można dostosować w tych zestawieniach: „wielkość liter”, „akcent”, „szerokość”, „typ kana” i „selektor wariacji” (począwszy od SQL Server 2017 i tylko dla zestawień japońskich). Ponadto niektóre z tych zestawień (gdy są używane z danymi Unicode) obsługują dodatkowe znaki (począwszy od SQL Server 2012). To podejście dotyczy zarówno danych, jak NVARCHAR i VARCHAR danych (nawet danych nieobsługujących kodu Unicode). Ma zastosowanie do VARCHARdanych nieobsługujących kodu Unicode , najpierw konwertując wewnętrznie wartość na Unicode, a następnie stosując reguły sortowania / porównywania.


Proszę zanotować:

  1. Nie ma uniwersalnego domyślnego sortowania dla programu SQL Server. Domyślne ustawienie instalacji różni się w zależności od bieżących ustawień regionalnych / językowych systemu operacyjnego w chwili instalacji (co niestety SQL_Latin1_General_CP1_CI_ASdotyczy systemów w języku angielskim w USA, więc proszę głosować na tę sugestię ). Można to zmienić podczas instalacji. To sortowanie na poziomie instancji ustawia następnie sortowanie dla [model]bazy danych, która jest szablonem używanym podczas tworzenia nowych baz danych, ale sortowanie można zmienić podczas wykonywania CREATE DATABASE, określając COLLATEklauzulę. To sortowanie na poziomie bazy danych jest używane w przypadku literałów zmiennych i literałów, a także domyślnych dla nowych (i zmienionych!) Kolumn, gdy COLLATEklauzula nie jest określona (tak jest w przypadku przykładowego kodu w pytaniu).
  2. Aby uzyskać więcej informacji na temat zestawień / kodowań / Unicode, odwiedź: Informacje o zestawieniach
Solomon Rutzky
źródło
5

Zazwyczaj jest to realizowane za pomocą tabel sortowania, które przypisują określoną ocenę każdemu znakowi. Procedura sortowania ma komparator, który wykorzystuje odpowiednią tabelę, domyślną lub jawną, do porównywania ciągów znak po znaku za pomocą ich wyników sortowania. Jeśli na przykład konkretna tabela zestawiania przypisuje wynik 1 do „a” i 201 do „A”, a niższy wynik w tej konkretnej implementacji oznacza wyższy priorytet, wówczas „a” będzie sortował przed „A”. Inna tabela może przypisywać wyniki wsteczne: 201 do „a” i 1 do „A”, a kolejność sortowania zostanie następnie odwrócona. Jeszcze inna tabela może przypisywać równe wyniki „a”, „A”, „Á” i „Å”, co prowadziłoby do porównania i sortowania bez rozróżniania wielkości liter i akcentów.

Podobnie, taki komparator oparty na tabeli zestawień stosowany podczas porównywania klucza indeksu z wartością podaną w predykacie.

mustaccio
źródło
1
Tylko do waszej informacji: te informacje są poprawne tylko pod względem używania zestawień SQL Server (tj. Tych o nazwach rozpoczynających się od SQL_), gdy są używane w VARCHARdanych. Nie jest to do końca prawdą w przypadku NVARCHARdanych lub VARCHARdanych podczas korzystania z sortowania w systemie Windows (nazwy nie zaczynające się od SQL_).
Solomon Rutzky