Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Obsługa UTF-8, SQL Server 2012 i UTF8String UDT

Tworzenie niestandardowego typu zdefiniowanego przez użytkownika za pomocą SQLCLR nie , w jakikolwiek sposób zapewni Ci zamiennik dowolnego typu natywnego. Jest to bardzo przydatne przy tworzeniu czegoś do obsługi specjalistycznych danych. Ale łańcuchy, nawet o innym kodowaniu, są dalekie od specjalizacji. Podążanie tą trasą dla danych ciągów zniszczyłoby jakąkolwiek użyteczność systemu, nie wspominając o wydajności, ponieważ nie byłoby możliwe użycie żadnego wbudowane funkcje łańcuchowe.

Gdybyś był w stanie zaoszczędzić cokolwiek na miejscu na dysku, te zyski zostałyby wymazane przez to, co stracisz na ogólnej wydajności. Przechowywanie UDT odbywa się poprzez serializację go do VARBINARY . Aby więc zrobić dowolne porównanie ciągów LUB sortowanie, poza porównaniem „binarnym” / „porządkowym”, musiałbyś przekonwertować wszystkie inne wartości, jedna po drugiej, z powrotem do UTF-8, aby następnie wykonać porównanie ciągów, które może uwzględniać różnice językowe. I ta konwersja musiałaby zostać wykonana w ramach UDT. Oznacza to, że podobnie jak typ danych XML, utworzysz UDT do przechowywania określonej wartości, a następnie udostępnisz metodę tego UDT, aby zaakceptować parametr ciągu w celu przeprowadzenia porównania (tj. Utf8String.Compare(alias.field1) lub, jeśli definiujesz operator dla typu, to Utf8string1 = Utf8string2 i mieć = operator pobiera ciąg znaków w kodowaniu UTF-8, a następnie wykonuje CompareInfo.Compare() ).

Oprócz powyższych rozważań należy również wziąć pod uwagę, że przekazywanie wartości tam iz powrotem przez interfejs API SQLCLR wiąże się z pewnym kosztem, szczególnie w przypadku korzystania z NVARCHAR(MAX) lub VARBINARY(MAX) w przeciwieństwie do NVARCHAR(1 - 4000) i VARBINARY(1 - 4000) odpowiednio (proszę nie mylić tego rozróżnienia jako sugerującego cokolwiek o używaniu SqlChars / SqlBytes vs SqlString / SqlBinary ).

Na koniec (przynajmniej jeśli chodzi o użycie UDT), proszę nie patrzeć poza fakt, że UDT, o który pytamy, to przykładowy kod . Jedyne odnotowane testy są czysto funkcjonalne, nie dotyczą skalowalności lub „wniosków wyciągniętych po pracy z tym przez rok”. Kod testu funkcjonalnego jest pokazany tutaj na następującej stronie CodePlex i należy się z nim zapoznać przed podjęciem tej decyzji, ponieważ daje on poczucie, w jaki sposób należałoby pisać zapytania, aby móc z nim współdziałać (co jest dobre dla pola lub dwa, ale nie dla większości / wszystkich pól tekstowych):

http://msftengprodsamples.codeplex.com /SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/Skrypty/Test.sql

Biorąc pod uwagę liczbę utrwalonych kolumn obliczeniowych i dodanych indeksów, czy naprawdę zaoszczędzono miejsce?;-)

Tam, gdzie problemem jest miejsce (dysk, pamięć itp.), masz trzy możliwości:

  1. Jeśli używasz programu SQL Server 2008 lub nowszego i korzystasz z wersji Enterprise Edition, możesz włączyć Kompresja danych . Kompresja danych może (ale nie „zawsze”) kompresować dane Unicode w NCHAR i NVARCHAR pola. Czynnikami decydującymi są:

    1. NCHAR(1 - 4000) i NVARCHAR(1 - 4000) użyj Standardowego schematu kompresji dla Unicode , ale tylko począwszy od programu SQL Server 2008 R2 I tylko w przypadku danych W WIERSZYCH, a nie PRZEPEŁNIENIE! To wydaje się być lepsze niż zwykły algorytm kompresji ROW/PAGE.
    2. NVARCHAR(MAX) i XML (i chyba także VARBINARY(MAX) , TEXT i NTEXT ) dane, które są IN ROW (nie poza wierszem na stronach LOB lub OVERFLOW) mogą być skompresowane co najmniej PAGE i być może także skompresowany ROW (nie jestem pewien co do tego ostatniego).
    3. Dowolne dane OFF ROW, LOB lub OVERLOW =Brak kompresji dla Ciebie!
  2. Jeśli używasz wersji starszej niż 2008 lub nie w Enterprise Edition, możesz mieć dwa pola:jedno VARCHAR i jeden NVARCHAR . Załóżmy na przykład, że przechowujesz adresy URL, które w większości składają się z podstawowych znaków ASCII (wartości od 0 do 127) i dlatego pasują do VARCHAR , ale czasami mają znaki Unicode. Twój schemat może zawierać następujące 3 pola:

      ...
      URLa VARCHAR(2048) NULL,
      URLu NVARCHAR(2048) NULL,
      URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
      CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
                        ([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
                    AND ([URLa] IS NULL OR [URLu] IS NULL))
    );
    

    W tym modelu tylko WYBIERZ z [URL] obliczona kolumna. W przypadku wstawiania i aktualizowania określasz, którego pola użyć, sprawdzając, czy konwersja zmienia przychodzącą wartość, która musi mieć wartość NVARCHAR typ:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. Jeśli masz pola, które powinny zawsze zawierać tylko znaki pasujące do określonej strony kodowej rozszerzonego zestawu znaków ASCII, użyj po prostu VARCHAR .

PS Żeby było jasne:nowy _SC Zestawienia wprowadzone w SQL Server 2012 pozwalają po prostu na:

  • wbudowane funkcje do prawidłowej obsługi znaków uzupełniających/par zastępczych oraz
  • zasady językowe dla znaków uzupełniających, które są używane do porządkowania i porównań

Ale nawet bez nowego _SC Sortowanie, nadal możesz przechowywać dowolny znak Unicode w pliku XML lub N - typ z przedrostkiem i pobierz go bez utraty danych. Jednak w przypadku używania starszych zestawień (tj. brak numeru wersji w nazwie), wszystkie znaki uzupełniające są sobie równe. Musisz użyć _90 i _100 Sortowanie, które przynajmniej umożliwiają porównywanie i sortowanie punktów binarnych / kodowych; nie mogą brać pod uwagę reguł językowych, ponieważ nie mają konkretnych mapowań znaków uzupełniających (a zatem nie mają wag ani reguł normalizacji).

Wypróbuj następujące:

IF (N'𤪆' = N'𤪆') SELECT N'𤪆' AS [TheLiteral], NCHAR(150150) AS [Generated];
IF (N'𤪆' = N'𤪇') SELECT N'𤪇' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'𤪆' COLLATE Tatar_90_CI_AI = N'𤪇' COLLATE Tatar_90_CI_AI)
       SELECT N'𤪇 COLLATE Tatar_90_CI_AI' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'𤪆' = N'?') SELECT N'?';

W bazie danych z domyślnym sortowaniem kończącym się na _SC , tylko pierwszy IF instrukcja zwróci zestaw wyników, a pole „Generated” pokaże poprawnie znaki.

Ale jeśli DB nie ma domyślnego sortowania kończącego się na _SC , a sortowanie nie jest _90 lub _100 sortowanie serii, a następnie pierwsze dwa IF instrukcje zwracają zestawy wyników, w których pole „Generated” zwróci NULL , a pole „Literał” wyświetla się poprawnie.

W przypadku danych Unicode sortowanie nie ma wpływu na fizyczne przechowywanie.

AKTUALIZACJA 2018-10-02

Chociaż nie jest to jeszcze realna opcja, SQL Server 2019 wprowadza natywną obsługę UTF-8 w VARCHAR / CHAR typy danych. Obecnie jest w nim zbyt wiele błędów, aby można było z niego korzystać, ale jeśli zostaną naprawione, jest to opcja dla niektórych scenariusze. Zobacz mój post, „Natywna obsługa UTF-8 w SQL Server 2019:Savior czy False Prophet? ”, aby uzyskać szczegółową analizę tej nowej funkcji.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak nadać uprawnienia (tabela) w SQL Server 2008?

  2. Use Case Statement w Join

  3. XQuery i identyfikatory węzłów

  4. Eksportuj dane serwera SQL do pliku CSV

  5. Jak dowiedzieć się, jakie tabele zawierają dane w pliku w programie SQL Server?