sql >> Database teknologi >  >> RDS >> Sqlserver

UTF-8 Support, SQL Server 2012 og UTF8String UDT

Oprettelse af en brugerdefineret brugerdefineret type via SQLCLR er ikke , på nogen måde, vil give dig en erstatning af enhver indfødt type. Det er meget praktisk til at skabe noget til at håndtere specialiserede data. Men strenge, selv af en anden kodning, er langt fra specialiserede. At gå denne vej for dine strengdata ville ødelægge enhver mængde af anvendelighed af dit system, for ikke at nævne ydeevne, da du ikke ville være i stand til at bruge nogle indbyggede strengfunktioner.

Hvis du var i stand til at spare noget på diskplads, ville disse gevinster blive slettet af, hvad du ville miste i den samlede ydeevne. Lagring af en UDT sker ved at serialisere den til en VARBINARY . Så for at gøre hvilket som helst strengsammenligning ELLER sortering, uden for en "binær" / "ordinær" sammenligning, skal du konvertere alle andre værdier, én efter én, tilbage til UTF-8 for derefter at udføre strengsammenligningen, der kan tage højde for sproglige forskelle. Og den konvertering skal udføres inden for UDT. Dette betyder, at du ligesom XML-datatypen ville oprette UDT'en til at holde en bestemt værdi og derefter afsløre en metode for denne UDT for at acceptere en strengparameter for at udføre sammenligningen (dvs. Utf8String.Compare(alias.field1) eller, hvis du definerer en operator for typen, så Utf8string1 = Utf8string2 og har = operatør få strengen i UTF-8-kodningen og derefter CompareInfo.Compare() ).

Ud over ovenstående overvejelser skal du også overveje, at det er en omkostning at sende værdier frem og tilbage gennem SQLCLR API'et, især når du bruger enten NVARCHAR(MAX) eller VARBINARY(MAX) i modsætning til NVARCHAR(1 - 4000) og VARBINARY(1 - 4000) (du må ikke forveksle denne skelnen som at antyde noget om brug af SqlChars / SqlBytes vs SqlString / SqlBinary ).

Endelig (i det mindste med hensyn til at bruge en UDT), skal du ikke se forbi det faktum, at den UDT, der bliver spurgt om, er eksempelkode . Den eneste noterede test er rent funktionel, intet omkring skalerbarhed eller "erfaringer efter at have arbejdet med dette i et år". Den funktionelle testkode er vist her på den følgende CodePlex-side og bør ses på, før du fortsætter med denne beslutning, da den giver en fornemmelse af, hvordan du skal skrive dine forespørgsler for at interagere med den (hvilket er fint for et felt eller to, men ikke for de fleste / alle strengfelter):

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

I betragtning af antallet af vedvarende beregnede kolonner og indekser tilføjet, blev der virkelig sparet plads?;-)

Hvor plads (disk, hukommelse osv.) er problemet, har du tre muligheder:

  1. Hvis du bruger SQL Server 2008 eller nyere og er på Enterprise Edition, så kan du aktivere Datakomprimering . Datakomprimering kan (men vil ikke "altid") komprimere Unicode-data i NCHAR og NVARCHAR felter. De afgørende faktorer er:

    1. NCHAR(1 - 4000) og NVARCHAR(1 - 4000) brug Standard Compression Scheme for Unicode , men kun startende i SQL Server 2008 R2, OG kun for IN ROW-data, ikke OVERFLOW! Dette ser ud til at være bedre end den almindelige ROW/PAGE-komprimeringsalgoritme.
    2. NVARCHAR(MAX) og XML (og jeg tror også VARBINARY(MAX) , TEXT og NTEXT ) data, der er I RÆKKE (ikke uden for række på LOB- eller OVERFLØD-sider) kan være mindst PAGE-komprimeret, og måske også ROW komprimeret (ikke sikker på denne sidste).
    3. Alle OFF ROW-data, LOB eller OVERLOW =Ingen komprimering for dig!
  2. Hvis du bruger en version ældre end 2008 eller ej på Enterprise Edition, kan du have to felter:et VARCHAR og en NVARCHAR . Lad os f.eks. sige, at du gemmer URL'er, som for det meste alle er basis-ASCII-tegn (værdier 0 - 127) og derfor passer ind i VARCHAR , men har nogle gange Unicode-tegn. Dit skema kan indeholde følgende 3 felter:

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

    I denne model du kun VÆLG fra [URL] beregnet kolonne. Til indsættelse og opdatering bestemmer du, hvilket felt der skal bruges ved at se, om konvertering ændrer den indgående værdi, som skal være af NVARCHAR type:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. Hvis du har felter, der kun bør have tegn, der passer ind i en bestemt kodeside i et udvidet ASCII-tegnsæt, så brug bare VARCHAR .

P.S. Bare for at få dette sagt for klarhedens skyld:den nye _SC Samlinger, der blev introduceret i SQL Server 2012, giver ganske enkelt mulighed for:

  • de indbyggede funktioner til korrekt håndtering af de supplerende tegn/surrogatpar, og
  • sproglige regler for supplerende tegn, der bruges til bestilling og sammenligninger

Men selv uden den nye _SC Sorteringer, kan du stadig gemme ethvert Unicode-tegn i en XML eller N -præfikset type, og hent den uden tab af data. Men når du bruger de ældre kollationer (dvs. intet versionsnummer i navnet), er alle supplerende tegn lig med hinanden. Du skal bruge _90 og _100 Samlinger, som i det mindste giver dig binære / kodepunkter sammenligninger og sortering; de kan ikke tage højde for sproglige regler, da de ikke har nogen særlige afbildninger af de supplerende tegn (og derfor ikke har nogen vægtning eller normaliseringsregler).

Prøv følgende:

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

I en DB med en standardsortering, der ender på _SC , kun den første IF sætning vil returnere et resultatsæt, og feltet "Genereret" vil vise tegnene korrekt.

Men hvis DB'en ikke har en standardsortering, der ender på _SC , og sorteringen er ikke en _90 eller _100 seriesortering, derefter de to første IF sætninger returnerer resultatsæt, hvori feltet "Genereret" returnerer NULL , og feltet "Literal" vises korrekt.

For Unicode-data har sorteringen ingen betydning for fysisk lagring.

OPDATERING 2018-10-02

Selvom dette ikke er en levedygtig mulighed endnu, introducerer SQL Server 2019 indbygget understøttelse af UTF-8 i VARCHAR / CHAR datatyper. Der er i øjeblikket for mange fejl med det til at det kan bruges, men hvis de er rettet, så er dette en mulighed for nogle scenarier. Se venligst mit indlæg, "Native UTF-8-understøttelse i SQL Server 2019:Frelser eller falsk profet? ", for en detaljeret analyse af denne nye funktion.




  1. Skinner 3.1. Heroku PGError:Operator findes ikke:tegnvarierende =heltal

  2. ALTER TABLE-tabel AUTO_INCREMENT =$x

  3. Hvordan fungerer det at hente data fra SQL Server til SqlDataReader?

  4. Hvordan CONVERT_TZ() virker i MariaDB