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):
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:
-
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
iNVARCHAR
pola. Czynnikami decydującymi są:NCHAR(1 - 4000)
iNVARCHAR(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.NVARCHAR(MAX)
iXML
(i chyba takżeVARBINARY(MAX)
,TEXT
iNTEXT
) 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).- Dowolne dane OFF ROW, LOB lub OVERLOW =Brak kompresji dla Ciebie!
-
Jeśli używasz wersji starszej niż 2008 lub nie w Enterprise Edition, możesz mieć dwa pola:jedno
VARCHAR
i jedenNVARCHAR
. 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ą doVARCHAR
, 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) );
-
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.