sql >> Database >  >> RDS >> Sqlserver

UTF-8-ondersteuning, SQL Server 2012 en de UTF8String UDT

Het maken van een aangepast door de gebruiker gedefinieerd type via SQLCLR is niet , op wat voor manier dan ook, om u een vervanging van elk native type te bezorgen. Het is erg handig om iets te maken om gespecialiseerde gegevens te verwerken. Maar strings, zelfs met een andere codering, zijn verre van gespecialiseerd. Als u deze route volgt voor uw stringgegevens, zou elke mate van bruikbaarheid van uw systeem worden vernietigd, om nog maar te zwijgen van de prestaties, aangezien u geen zou kunnen gebruiken ingebouwde tekenreeksfuncties.

Als u iets op schijfruimte zou kunnen besparen, zou die winst teniet worden gedaan door wat u zou verliezen aan algehele prestaties. Het opslaan van een UDT gebeurt door het te serialiseren naar een VARBINARY . Dus om elke . te doen tekenreeksvergelijking OF sortering, buiten een "binaire" / "ordinale" vergelijking, zou u alle andere waarden één voor één terug moeten converteren naar UTF-8 om vervolgens de tekenreeksvergelijking uit te voeren die rekening kan houden met taalkundige verschillen. En die conversie zou binnen de UDT moeten gebeuren. Dit betekent dat u, net als het XML-gegevenstype, de UDT zou maken om een ​​bepaalde waarde vast te houden, en vervolgens een methode van die UDT zou tonen om een ​​stringparameter te accepteren om de vergelijking uit te voeren (d.w.z. Utf8String.Compare(alias.field1) of, als u een operator voor het type definieert, dan Utf8string1 = Utf8string2 en hebben de = operator de string in de UTF-8-codering ophalen en vervolgens de CompareInfo.Compare() uitvoeren ).

Naast de bovenstaande overwegingen, moet u er ook rekening mee houden dat het heen en weer doorgeven van waarden via de SQLCLR-API kosten met zich meebrengt, vooral bij gebruik van NVARCHAR(MAX) of VARBINARY(MAX) in tegenstelling tot NVARCHAR(1 - 4000) en VARBINARY(1 - 4000) respectievelijk (verwar dit onderscheid niet als iets over het gebruik van SqlChars / SqlBytes vs SqlString / SqlBinary ).

Tot slot (tenminste wat betreft het gebruik van een UDT), kijk alstublieft niet verder dan het feit dat de UDT waarnaar wordt gevraagd voorbeeldcode is . De enige test die wordt opgemerkt, is puur functioneel, niets rond schaalbaarheid of "geleerde lessen na een jaar hiermee te hebben gewerkt". De functionele testcode wordt hier getoond op de volgende CodePlex-pagina en moet worden bekeken voordat u doorgaat met deze beslissing, omdat het een idee geeft van hoe u uw vragen zou moeten schrijven om ermee te werken (wat prima is voor een veld of twee, maar niet voor de meeste / alle tekenreeksvelden):

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

Is er, gezien het aantal persistente berekende kolommen en indexen dat is toegevoegd, echt ruimte bespaard?;-)

Waar ruimte (schijf, geheugen, enz.) de zorg is, heb je drie opties:

  1. Als u SQL Server 2008 of nieuwer gebruikt en Enterprise Edition gebruikt, kunt u Gegevenscompressie . Gegevenscompressie kan (maar zal niet "altijd") Unicode-gegevens comprimeren in NCHAR en NVARCHAR velden. De bepalende factoren zijn:

    1. NCHAR(1 - 4000) en NVARCHAR(1 - 4000) gebruik het Standaard compressieschema voor Unicode , maar alleen starten in SQL Server 2008 R2, EN alleen voor IN ROW-gegevens, niet OVERFLOW! Dit lijkt beter te zijn dan het reguliere ROW / PAGE-compressiealgoritme.
    2. NVARCHAR(MAX) en XML (en ik denk ook VARBINARY(MAX) , TEXT , en NTEXT ) gegevens die IN RIJ zijn (niet uit de rij in LOB- of OVERFLOW-pagina's) kunnen ten minste PAGE-gecomprimeerd zijn, en misschien ook ROW gecomprimeerd (niet zeker van deze laatste).
    3. Alle OFF ROW-gegevens, LOB of OVERLOW =geen compressie voor u!
  2. Als u een versie gebruikt die ouder is dan 2008 of niet op Enterprise Edition, kunt u twee velden hebben:één VARCHAR en één NVARCHAR . Laten we bijvoorbeeld zeggen dat u URL's opslaat die meestal allemaal basis ASCII-tekens zijn (waarden 0 - 127) en dus passen in VARCHAR , maar hebben soms Unicode-tekens. Uw schema kan de volgende 3 velden bevatten:

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

    In dit model heb je alleen SELECTEER uit de [URL] berekende kolom. Voor het invoegen en bijwerken bepaalt u welk veld u moet gebruiken door te kijken of het converteren de inkomende waarde verandert, die van NVARCHAR moet zijn typ:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. Als u velden heeft die alleen tekens mogen bevatten die in een bepaalde codepagina van een uitgebreide ASCII-tekenset passen, gebruik dan gewoon VARCHAR .

PS Even voor de duidelijkheid:de nieuwe _SC Collaties die zijn geïntroduceerd in SQL Server 2012 zorgen voor:

  • de ingebouwde functies om de aanvullende tekens / surrogaatparen correct af te handelen, en
  • taalregels voor aanvullende tekens die worden gebruikt voor het ordenen en vergelijken

Maar zelfs zonder de nieuwe _SC Collaties, je kunt nog steeds elk Unicode-teken opslaan in een XML of N -prefix type, en haal het op zonder gegevensverlies. Bij gebruik van de oudere sorteringen (d.w.z. geen versienummer in de naam), zijn alle aanvullende tekens aan elkaar gelijk. U moet de _90 . gebruiken en _100 Verzamelingen die u op zijn minst binaire / codepuntvergelijkingen en sortering opleveren; ze kunnen geen rekening houden met taalkundige regels omdat ze geen specifieke toewijzingen van de aanvullende tekens hebben (en dus geen gewichten of normalisatieregels hebben).

Probeer het volgende:

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

In een DB met een standaard sortering die eindigt op _SC , alleen de eerste IF statement retourneert een resultatenset en het veld "Gegenereerd" zal de tekens correct weergeven.

Maar als de database geen standaard sortering heeft die eindigt op _SC , en de sortering is geen _90 of _100 seriesortering, dan de eerste twee IF statements retourneren resultaatsets waarin het veld "Generated" NULL als resultaat geeft , en het veld "Letterlijk" wordt correct weergegeven.

Voor Unicode-gegevens heeft de sortering geen invloed op fysieke opslag.

UPDATE 02-10-2018

Hoewel dit nog geen haalbare optie is, introduceert SQL Server 2019 native ondersteuning voor UTF-8 in VARCHAR / CHAR gegevenstypen. Er zijn momenteel te veel bugs om het te gebruiken, maar als ze zijn opgelost, dan is dit een optie voor sommige scenario's. Zie mijn bericht, "Native UTF-8-ondersteuning in SQL Server 2019:redder of valse profeet? ", voor een gedetailleerde analyse van deze nieuwe functie.




  1. MYSQL:Leegstaande / bezette kamers zoals nu

  2. Snaren op de juiste manier splitsen - of de op één na beste manier

  3. Ingewikkelde SQL-query - items vinden die overeenkomen met meerdere verschillende externe sleutels

  4. Lijst met alle index- en indexkolommen in SQL Server DB