Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Поддръжка на UTF-8, SQL Server 2012 и UTF8String UDT

Създаването на потребителски дефиниран от потребителя тип чрез SQLCLR не е , по какъвто и да е начин, ще ви осигури заместител на произволен роден тип. Много е удобно за създаване на нещо, което да обработва специализирани данни. Но низовете, дори с различно кодиране, далеч не са специализирани. Тръгването по този път за вашите низови данни би унищожило каквато и да е използваемост на вашата система, да не говорим за производителността, тъй като не бихте могли да използвате никое вградени низови функции.

Ако успеете да спестите нещо от дисковото пространство, тези печалби ще бъдат изтрити от това, което ще загубите в цялостната производителност. Съхраняването на UDT се извършва чрез сериализирането му в VARBINARY . Така че, за да направите всяко сравнение на низове ИЛИ сортиране, извън "двоично" / "редно" сравнение, ще трябва да конвертирате всички други стойности, една по една, обратно в UTF-8, за да направите след това сравнение на низове, което може да отчете езиковите разлики. И това преобразуване ще трябва да се извърши в UDT. Това означава, че подобно на XML типа данни, вие бихте създали UDT, който да съдържа конкретна стойност, и след това да изложите метод на този UDT, за да приеме низов параметър за извършване на сравнението (т.е. Utf8String.Compare(alias.field1) или, ако дефинирате оператор за типа, тогава Utf8string1 = Utf8string2 и имат = вземете низа в UTF-8 кодирането и след това направете CompareInfo.Compare() ).

В допълнение към горните съображения, вие също трябва да имате предвид, че предаването на стойности напред и назад през SQLCLR API има цена, особено когато използвате NVARCHAR(MAX) или VARBINARY(MAX) за разлика от NVARCHAR(1 - 4000) и VARBINARY(1 - 4000) съответно (моля, не бъркайте това разграничение като предполагащо нещо относно използването на SqlChars / SqlBytes срещу SqlString / SqlBinary ).

И накрая (поне по отношение на използването на UDT), моля, не пренебрегвайте факта, че UDT, за който се пита, е примерен код . Единственото отбелязано тестване е чисто функционално, нищо около скалируемостта или „научените уроци след работа с това в продължение на една година“. Функционалният тестов код е показан тук на следната страница на CodePlex и трябва да бъде разгледан, преди да продължите с това решение, тъй като дава представа как ще трябва да напишете вашите заявки, за да взаимодействате с него (което е добре за поле или две, но не за повечето / всички низови полета):

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

Имайки предвид броя на добавените постоянни изчислени колони и индекси, наистина ли е спестено място?;-)

Когато пространството (диск, памет и т.н.) е проблем, имате три възможности:

  1. Ако използвате SQL Server 2008 или по-нова версия и сте в Enterprise Edition, тогава можете да активирате Компресиране на данни . Компресирането на данни може (но няма да "винаги") компресира Unicode данни в NCHAR и NVARCHAR полета. Определящите фактори са:

    1. NCHAR(1 - 4000) и NVARCHAR(1 - 4000) използвайте Стандартна схема за компресиране за Unicode , но само като се стартира в SQL Server 2008 R2 И само за IN ROW данни, а не за OVERFLOW! Това изглежда е по-добро от обикновения алгоритъм за компресиране на РЕД/СТРАНИЦА.
    2. NVARCHAR(MAX) и XML (и предполагам също VARBINARY(MAX) , TEXT и NTEXT ) данни, които са IN ROW (не извън реда в LOB или OVERFLOW страници), могат да бъдат поне PAGE компресирани и може би също ROW компресиран (не съм сигурен за последния).
    3. Всички данни OFF ROW, LOB или OVERLOW =Без компресиране за вас!
  2. Ако използвате версия, по-стара от 2008 г. или не в Enterprise Edition, можете да имате две полета:едно VARCHAR и един NVARCHAR . Например, да кажем, че съхранявате URL адреси, които са предимно основни ASCII знаци (стойности 0 - 127) и следователно се вписват в VARCHAR , но понякога имат Unicode знаци. Вашата схема може да включва следните 3 полета:

      ...
      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))
    );
    

    В този модел само ИЗБЕРЕТЕ от [URL] изчислена колона. За вмъкване и актуализиране вие ​​определяте кое поле да използвате, като видите дали преобразуването променя входящата стойност, която трябва да бъде NVARCHAR тип:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. Ако имате полета, които трябва да съдържат само знаци, които се вписват в конкретна кодова страница на разширен ASCII набор от знаци, тогава просто използвайте VARCHAR .

P.S. Само за да бъде посочено това за яснота:новият _SC Колациите, които бяха въведени в SQL Server 2012, просто позволяват:

  • вградените функции за правилно боравене с допълнителните знаци/сурогатни двойки и
  • лингвистични правила за допълнителни знаци, които се използват за подреждане и сравнения

Но дори и без новия _SC Съпоставяне, все още можете да съхранявате всеки Unicode знак в XML или N -предварителен тип и го извличайте без загуба на данни. Въпреки това, когато се използват по-старите съпоставки (т.е. без номер на версията в името), всички допълнителни знаци се приравняват един към друг. Трябва да използвате _90 и _100 Сравнявания, които най-малко ви осигуряват сравнения и сортиране на двоични/кодови точки; те не могат да вземат под внимание лингвистичните правила, тъй като нямат конкретни преобразувания на допълнителните знаци (и следователно нямат тегла или правила за нормализиране).

Опитайте следното:

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'?';

В база данни с сортиране по подразбиране, завършващо на _SC , само първият IF операторът ще върне набор от резултати и полето "Генерирано" ще показва правилно символите.

Но ако DB няма подреждане по подразбиране, завършващо на _SC и сортирането не е _90 или _100 серийно съпоставяне, след това първите две IF операторите връщат набори от резултати, където полето "Генерирано" ще върне NULL и полето „Литерал“ се показва правилно.

За Unicode данни съпоставянето няма отношение към физическото съхранение.

АКТУАЛИЗАЦИЯ 2018-10-02

Въпреки че това все още не е жизнеспособна опция, SQL Server 2019 въвежда собствена поддръжка за UTF-8 в VARCHAR / CHAR типове данни. В момента има твърде много грешки в него, за да може да се използва, но ако бъдат коригирани, това е опция за някои сценарии. Моля, вижте публикацията ми, "Нативна поддръжка на UTF-8 в SQL Server 2019:Спасител или фалшив пророк? “, за подробен анализ на тази нова функция.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Разлика между подзаявка и корелирана подзаявка

  2. В SQL Server 2005, как мога да напиша заявка за изброяване на всички данни за влизане, тяхната сървърна роля, съответстващ потребител във всички db, db роля?

  3. Дублиращи се записи с различно времево клеймо

  4. импортиране на данни от една таблица в друга таблица

  5. Как да създадете изглед с 14 000 колони в него?