Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

UTF-8-Unterstützung, SQL Server 2012 und der UTF8String-UDT

Das Erstellen eines benutzerdefinierten benutzerdefinierten Typs über SQLCLR ist nicht , in irgendeiner Weise erhalten Sie einen Ersatz für jeden nativen Typ. Es ist sehr praktisch, etwas zu erstellen, um mit speziellen Daten umzugehen. Aber Zeichenfolgen, selbst mit einer anderen Codierung, sind alles andere als spezialisiert. Wenn Sie diesen Weg für Ihre Zeichenfolgendaten gehen, würde dies die Benutzerfreundlichkeit Ihres Systems zerstören, ganz zu schweigen von der Leistung, da Sie keine verwenden könnten eingebaute String-Funktionen.

Wenn Sie etwas Speicherplatz sparen könnten, würden diese Gewinne durch das, was Sie an Gesamtleistung verlieren würden, zunichte gemacht. Das Speichern eines UDT erfolgt durch Serialisierung in ein VARBINARY . Also, um beliebige zu tun Zeichenfolgenvergleich ODER Sortierung, außerhalb eines "binären" / "ordinalen" Vergleichs, müssten Sie alle anderen Werte einzeln zurück in UTF-8 konvertieren, um dann den Zeichenfolgenvergleich durchzuführen, der sprachliche Unterschiede berücksichtigen kann. Und diese Konvertierung müsste innerhalb des UDT erfolgen. Das bedeutet, dass Sie wie beim XML-Datentyp den UDT erstellen würden, um einen bestimmten Wert zu speichern, und dann eine Methode dieses UDT verfügbar machen würden, um einen Zeichenfolgenparameter für den Vergleich zu akzeptieren (z. B. Utf8String.Compare(alias.field1) oder, wenn ein Operator für den Typ definiert wird, dann Utf8string1 = Utf8string2 und haben den = Operator erhält die Zeichenfolge in der UTF-8-Codierung und führt dann CompareInfo.Compare() aus ).

Zusätzlich zu den obigen Überlegungen müssen Sie auch berücksichtigen, dass das Hin- und Hergeben von Werten durch die SQLCLR-API mit Kosten verbunden ist, insbesondere wenn Sie entweder NVARCHAR(MAX) verwenden oder VARBINARY(MAX) im Gegensatz zu NVARCHAR(1 - 4000) und VARBINARY(1 - 4000) (Bitte verwechseln Sie diese Unterscheidung nicht damit, dass sie etwas über die Verwendung von SqlChars impliziert / SqlBytes vs SqlString / SqlBinary ).

Schließlich (zumindest in Bezug auf die Verwendung eines UDT) sehen Sie bitte nicht über die Tatsache hinweg, dass es sich bei dem abgefragten UDT um Beispielcode handelt . Die einzigen Tests, die erwähnt werden, sind rein funktional, nichts über Skalierbarkeit oder "Lektionen, die nach einjähriger Arbeit damit gelernt wurden". Der funktionale Testcode wird hier auf der folgenden CodePlex-Seite gezeigt und sollte betrachtet werden, bevor Sie mit dieser Entscheidung fortfahren, da er einen Eindruck davon vermittelt, wie Sie Ihre Abfragen schreiben müssten, um damit zu interagieren (was für ein Feld oder zwei, aber nicht für die meisten / alle String-Felder):

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

Wurde angesichts der Anzahl der hinzugefügten persistenten berechneten Spalten und Indizes wirklich Speicherplatz gespart?;-)

Wenn Platz (Festplatte, Arbeitsspeicher usw.) wichtig ist, haben Sie drei Möglichkeiten:

  1. Wenn Sie SQL Server 2008 oder neuer verwenden und die Enterprise Edition verwenden, können Sie Datenkomprimierung . Die Datenkomprimierung kann (aber nicht "immer") Unicode-Daten in NCHAR komprimieren und NVARCHAR Felder. Die bestimmenden Faktoren sind:

    1. NCHAR(1 - 4000) und NVARCHAR(1 - 4000) Verwenden Sie das Standardkomprimierungsschema für Unicode , aber erst ab SQL Server 2008 R2 UND nur für IN ROW-Daten, nicht OVERFLOW! Dies scheint besser zu sein als der normale ROW/PAGE-Komprimierungsalgorithmus.
    2. NVARCHAR(MAX) und XML (und ich denke auch VARBINARY(MAX) , TEXT , und NTEXT ) Daten, die IN ROW (nicht außerhalb der Zeile in LOB- oder OVERFLOW-Seiten) sind, können mindestens PAGE-komprimiert sein und vielleicht auch ROW komprimiert (bei letzterem bin ich mir nicht sicher).
    3. Alle OFF ROW-Daten, LOB oder OVERLOW =Keine Komprimierung für Sie!
  2. Wenn Sie eine ältere Version als 2008 oder nicht auf Enterprise Edition verwenden, können Sie zwei Felder haben:ein VARCHAR und ein NVARCHAR . Nehmen wir zum Beispiel an, Sie speichern URLs, die hauptsächlich ASCII-Basiszeichen (Werte 0 - 127) sind und daher in VARCHAR passen , haben aber manchmal Unicode-Zeichen. Ihr Schema kann die folgenden 3 Felder enthalten:

      ...
      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 diesem Modell sind Sie nur SELECT aus [URL] berechnete Spalte. Zum Einfügen und Aktualisieren bestimmen Sie, welches Feld verwendet werden soll, indem Sie sehen, ob die Konvertierung den eingehenden Wert ändert, der NVARCHAR sein muss Typ:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. Wenn Sie Felder haben, die immer nur Zeichen enthalten sollen, die in eine bestimmte Codepage eines erweiterten ASCII-Zeichensatzes passen, dann verwenden Sie einfach VARCHAR .

P.S. Nur zur Verdeutlichung:der neue _SC Sortierungen, die in SQL Server 2012 eingeführt wurden, ermöglichen einfach Folgendes:

  • die eingebauten Funktionen, um die ergänzenden Zeichen/Ersatzpaare richtig zu handhaben, und
  • sprachliche Regeln für ergänzende Zeichen, die zum Ordnen und Vergleichen verwendet werden

Aber auch ohne den neuen _SC Sortierungen können Sie weiterhin beliebige Unicode-Zeichen in einem XML- oder N-Format speichern -Präfixtyp und rufen Sie ihn ohne Datenverlust ab. Bei Verwendung der älteren Collations (d. h. keine Versionsnummer im Namen) sind jedoch alle ergänzenden Zeichen gleichbedeutend. Sie müssen den _90 verwenden und _100 Zusammenstellungen, die Ihnen zumindest Binär-/Codepunktvergleiche und Sortierungen ermöglichen; sie können keine linguistischen Regeln berücksichtigen, da sie keine besonderen Zuordnungen der ergänzenden Zeichen haben (und daher keine Gewichtungen oder Normalisierungsregeln haben).

Versuchen Sie Folgendes:

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 einer Datenbank mit einer Standardsortierung, die auf _SC endet , nur das erste IF -Anweisung wird eine Ergebnismenge zurückgeben, und das Feld "Generiert" zeigt die Zeichen korrekt an.

Aber wenn die DB keine Standardsortierung hat, die mit _SC endet , und die Sortierung ist kein _90 oder _100 Seriensortierung, dann die ersten beiden IF Anweisungen geben Ergebnissätze zurück, wobei das Feld "Generiert" NULL zurückgibt , und das Feld "Literal" wird korrekt angezeigt.

Bei Unicode-Daten hat die Sortierung keinen Einfluss auf die physische Speicherung.

UPDATE 02.10.2018

Obwohl dies noch keine praktikable Option ist, führt SQL Server 2019 die native Unterstützung für UTF-8 in VARCHAR ein / CHAR Datentypen. Derzeit gibt es zu viele Fehler, als dass es verwendet werden könnte, aber wenn sie behoben sind, dann ist dies eine Option für einige Szenarien. Bitte lesen Sie meinen Beitrag „Native UTF-8-Unterstützung in SQL Server 2019:Retter oder falscher Prophet? ", für eine detaillierte Analyse dieser neuen Funktion.