it-swarm.com.de

Wann wird "nvarchar / nchar" mit SQL Server 2019 verwendet?

Mit SQL Server 2019 führt Microsoft TF-8-Unterstützung für die Datentypen CHAR und VARCHAR ein und sagt:

Diese Funktion kann je nach verwendetem Zeichensatz zu erheblichen Speichereinsparungen führen. Wenn Sie beispielsweise einen vorhandenen Spaltendatentyp mit ASCII Zeichenfolgen) von NCHAR (10) in CHAR (10) unter Verwendung einer UTF-8-fähigen Sortierung ändern, wird der Speicherbedarf um fast 50% reduziert Die Reduzierung ist darauf zurückzuführen, dass NCHAR (10) 22 Byte für die Speicherung benötigt, während CHAR (10) 12 Byte für dieselbe Unicode-Zeichenfolge benötigt.

UTF-8 scheint nterstützung jedes Skript zu sein, daher können wir grundsätzlich damit beginnen, Unicode-Daten in den Spalten varchar und char zu speichern. Und wie in der Dokumentation erwähnt, kann dies die Größe von Tabellen und Indizes verringern, und von dort aus können wir eine noch bessere Leistung erzielen, da weniger Daten gelesen werden.

Ich frage mich, ob dies bedeutet, dass wir aufhören können, nvarchar und nchar Spalten zu verwenden, die UTF-16 implementieren.

Kann jemand ein Szenario und einen Grund angeben, die char-Datentypen nicht mit UTF -Codierung zu verwenden und weiterhin die n-chars-Datentypen zu verwenden?

11
gotqn

this can reduziert die Größe von Tabellen und Indizes (Hervorhebung hinzugefügt)

Eine Verkleinerung ist nur möglich, wenn die meisten der Zeichen im Wesentlichen [space], 0 - 9, A - Z, a - z Sind. und einige grundlegende Interpunktion. Außerhalb dieses spezifischen Zeichensatzes (in der Praxis Standard ASCII Werte 32 - 126)) sind Sie bestenfalls gleich groß wie NVARCHAR/UTF-16 oder in vielen Fällen größer.

Ich plane, die Daten zu migrieren, da ich glaube, dass das Lesen von weniger Daten zu einer besseren Leistung des Systems führen wird.

Achtung. UTF-8 ist kein magischer "Alles reparieren" -Schalter. Wenn alle anderen Dinge gleich sind, verbessert weniger Lesen die Leistung. Aber hier sind "alle anderen Dinge" nicht gleich. Selbst beim Speichern von nur Standard ASCII Zeichen) (was bedeutet: Alle Zeichen sind 1 Byte und benötigen daher die Hälfte des Speicherplatzes im Vergleich zum Speichern in NVARCHAR ) gibt es eine leichte Leistungsminderung für die Verwendung von UTF-8. Ich glaube, das Problem ist darauf zurückzuführen, dass UTF-8 eine Codierung mit variabler Länge ist, was bedeutet, dass jedes Byte so interpretiert werden muss, wie es gelesen wird, um zu wissen, ob es ist ein vollständiges Zeichen oder wenn das nächste Byte ein Teil davon ist. Dies bedeutet, dass alle Zeichenfolgenoperationen am Anfang beginnen und byteweise fortfahren müssen. Andererseits ist NVARCHAR/UTF-16 Immer 2 Bytes (sogar Zusatzzeichen bestehen aus zwei 2-Byte-Codepunkten), sodass alles in 2-Byte-Blöcken gelesen werden kann.

In meinen Tests ergab das Speichern der Daten als UTF-8 selbst mit nur standard ASCII) keine Einsparung von verstrichener Zeit, war jedoch für die CPU-Zeit definitiv schlechter Und das ohne Datenkomprimierung, so dass zumindest weniger Speicherplatz verwendet wurde. Bei Verwendung der Komprimierung war der für UTF-8 erforderliche Speicherplatz jedoch nur 1% - 1,5% kleiner. Somit praktisch keine Speicherplatzersparnis und dennoch höhere CPU-Zeit für UTF-8.

Bei Verwendung von NVARCHAR(MAX) wird es komplizierter, da die Unicode-Komprimierung mit diesem Datentyp nicht funktioniert, selbst wenn der Wert klein genug ist, um in einer Zeile gespeichert zu werden. Wenn die Daten jedoch klein genug sind, sollten sie dennoch von der Zeilen- oder Seitenkomprimierung profitieren (in diesem Fall werden sie tatsächlich schneller als UTF-8). Off-Row-Daten können jedoch keine Komprimierung verwenden. Wenn Sie die Tabelle jedoch zu einem Clustered Columnstore-Index machen, wird die Größe von NVARCHAR(MAX) erheblich reduziert (auch wenn sie bei Verwendung des Clustered Columnstore-Index immer noch geringfügig größer als UTF-8 ist).

Kann jemand ein Szenario und einen Grund angeben, die char-Datentypen nicht mit UTF-Codierung zu verwenden

Bestimmt. Tatsächlich finde ich in den meisten Fällen keinen zwingenden Grund, es zu verwenden. Das einzige Szenario, das wirklich von UTF-8 profitiert, ist:

  1. Daten sind meistens Standard ASCII (Werte 0 - 127)
  2. Es muss Unicode sein, da möglicherweise einen größeren Zeichenbereich speichern muss, als auf einer einzelnen 8-Bit-Codepage verfügbar ist (d. H. VARCHAR).
  3. Die meisten Daten werden außerhalb der Zeile gespeichert (sodass die Seitenkomprimierung nicht einmal funktioniert).
  4. Sie verfügen über genügend Daten, die Sie aus Gründen der Nichtabfrageleistung benötigen/reduzieren möchten (z. B. Sicherungsgröße reduzieren, Zeit für Sicherung/Wiederherstellung reduzieren usw.)
  5. Sie können den Clustered Columnstore Index nicht verwenden (möglicherweise verschlechtert die Verwendung der Tabelle in diesem Fall die Leistung?)

Meine Tests haben gezeigt, dass NVARCHAR in fast allen Fällen schneller war, insbesondere wenn mehr Daten vorhanden waren. Tatsächlich benötigten 21.000 Zeilen mit durchschnittlich 5.000 Zeichen pro Zeile 165 MB für UTF-8 und 236 MB für NVARCHAR unkomprimiert. Und doch war das NVARCHAR in der verstrichenen Zeit 2x schneller und in der CPU-Zeit mindestens 2x schneller (manchmal mehr). Trotzdem wurden 71 MB mehr auf der Festplatte benötigt.

Abgesehen davon würde ich die Verwendung von UTF-8, zumindest ab CTP 2, aufgrund einer Vielzahl von Fehlern, die ich in dieser Funktion gefunden habe, immer noch nicht empfehlen.

Eine detaillierte Analyse dieser neuen Funktion, einschließlich einer Erläuterung der Unterschiede zwischen UTF-16 und UTF-8 sowie einer Auflistung dieser Fehler, finden Sie in meinem Beitrag:

Native UTF-8-Unterstützung in SQL Server 2019: Retter oder falscher Prophet?

6
Solomon Rutzky

Die UTF-8-Unterstützung bietet Ihnen eine Reihe neuer Optionen. Mögliche Platzersparnisse (ohne Zeilen- oder Seitenkomprimierung ) sind eine Überlegung, aber die Auswahl von Typ und Codierung sollte wahrscheinlich hauptsächlich auf der Grundlage der tatsächlichen Anforderungen für Vergleich, Sortierung, Datenimport erfolgen und exportieren.

Möglicherweise müssen Sie mehr ändern, als Sie denken, da z. Ein nchar(1) -Typ stellt zwei Bytes Speicher bereit. Das reicht aus, um ein beliebiges Zeichen in BMP zu speichern (Codepunkte 000000 bis 00FFFF). Einige der Zeichen in diesem Bereich würden in UTF-8 mit nur 1 Byte codiert, während andere 2 oder sogar 3 Bytes benötigen würden (siehe diese Vergleichstabelle für weitere Details). Um sicherzustellen, dass derselbe Zeichensatz in UTF-8 abgedeckt wird, ist char(3) erforderlich.

Zum Beispiel:

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 char(1) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

gibt den bekannten Fehler:

Meldung 8152, Ebene 16, Status 30, Zeile xxx
String oder Binärdaten würden abgeschnitten werden.

Oder wenn das Ablaufverfolgungsflag 460 aktiv ist:

Nachricht 2628, Ebene 16, Status 1, Zeile xxx
Zeichenfolge oder Binärdaten werden in Tabelle '@T', Spalte 'UTF8' abgeschnitten. Abgeschnittener Wert: ''.

Durch Erweitern der UTF8-Spalte auf char(2) oder varchar(2) wird der Fehler für NCHAR(911) behoben:

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 varchar(2) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

Wenn es jedoch z.B. NCHAR(8364) müssten Sie die Spalte weiter erweitern, um char(3) oder varchar(3).

Beachten Sie auch, dass die UTF-8-Kollatierungen alle zusätzliche Zeichen verwenden, also funktioniert nicht mit Replikation.

Abgesehen von allem anderen ist die UTF-8-Unterstützung derzeit nur in der Vorschau verfügbar und daher nicht für die Produktion verfügbar.

12
Paul White 9