Frage

Ich arbeite an einer Datenbank für eine kleine Web-App an meiner Schule SQL Server 2005.
Ich sehe ein paar Denkschulen zu diesem Thema varchar vs nvarchar:

  1. Verwenden varchar Es sei denn, Sie haben mit vielen internationalisierten Daten zu tun, dann verwenden Sie nvarchar.
  2. Benutz einfach nvarchar für alles.

Ich fange an, die Vorzüge von Ansicht 2 zu erkennen.Ich weiß, dass nvarchar doppelt so viel Platz beansprucht, aber das ist nicht unbedingt ein großes Problem, da hier nur Daten für ein paar hundert Schüler gespeichert werden.Meiner Meinung nach wäre es am einfachsten, sich darüber keine Sorgen zu machen und einfach zuzulassen, dass alles Nvarchar verwendet.Oder fehlt mir etwas?

War es hilfreich?

Lösung

Verwenden Sie immer nvarchar.

Für die meisten Anwendungen benötigen Sie die Doppelbyte-Zeichen möglicherweise nie.Wenn Sie jedoch Doppelbyte-Sprachen unterstützen müssen und in Ihrem Datenbankschema nur Einzelbyte-Unterstützung vorhanden ist, ist es sehr kostspielig, in der gesamten Anwendung Änderungen vorzunehmen.

Die Kosten für die Migration einer Anwendung von Varchar nach Nvarchar werden viel höher sein als der kleine zusätzliche Speicherplatz, den Sie in den meisten Anwendungen benötigen.

Andere Tipps

Der Speicherplatz ist nicht das Problem...aber Speicher und Leistung werden es sein.Verdoppelung der Seitenlesevorgänge, doppelte Indexgröße, seltsames LIKE und = konstantes Verhalten usw

Müssen Sie chinesische Schrift usw. speichern?Ja oder nein...

Und von MS BOL“Speicher- und Leistungsauswirkungen von Unicode"

Bearbeiten:

Aktuelle SO-Frage, die hervorhebt, wie schlecht die Nvarchar-Leistung sein kann ...

SQL Server verbraucht beim Durchsuchen von Nvarchar-Zeichenfolgen eine hohe CPU-Auslastung

Seien Sie konsequent!Das Verknüpfen eines VARCHAR mit einem NVARCHAR hat einen großen Leistungseinbruch.

nvarchar wird einen erheblichen Overhead in Bezug auf Arbeitsspeicher, Speicher, Arbeitssatz und Indizierung verursachen, sofern die Spezifikationen dies wirklich vorschreiben niemals notwendig sein, kümmere dich nicht darum.

Ich hätte keine feste Regel „immer nvarchar“, da dies in vielen Situationen völlige Verschwendung sein kann – insbesondere ETL von ASCII/EBCDIC oder Bezeichnern und Codespalten, bei denen es sich oft um Schlüssel und Fremdschlüssel handelt.

Andererseits gibt es viele Fälle von Spalten, bei denen ich diese Frage auf jeden Fall frühzeitig stellen würde, und wenn ich nicht sofort eine eindeutige Antwort erhalten würde, würde ich die Spalte zu nvarchar machen.

Für Ihre Anwendung ist nvarchar in Ordnung, da die Datenbankgröße klein ist.Zu sagen „Immer Nvarchar verwenden“ ist eine starke Vereinfachung.Wenn Sie Dinge wie Kanji oder andere verrückte Zeichen nicht speichern müssen, verwenden Sie VARCHAR. Dadurch wird viel weniger Platz benötigt.Mein Vorgänger an meinem jetzigen Arbeitsplatz hat etwas mit NVARCHAR entworfen, als es nicht benötigt wurde.Wir haben es kürzlich auf VARCHAR umgestellt und 15 GB nur für diese Tabelle gespart (in die viel geschrieben wurde).Wenn Sie dann über einen Index für diese Tabelle verfügen und diese Spalte einschließen oder einen zusammengesetzten Index erstellen möchten, haben Sie einfach die Größe Ihrer Indexdatei erhöht.

Seien Sie bei Ihrer Entscheidung einfach überlegt;In der SQL-Entwicklung und bei Datendefinitionen scheint es selten eine „Standardantwort“ zu geben (außer natürlich, Cursor um jeden Preis zu vermeiden).

Ich zögere, hier noch eine weitere Antwort hinzuzufügen, da es bereits einige gibt, aber es müssen einige Punkte angesprochen werden, die entweder nicht oder nicht klar dargelegt wurden.

Erste: Tun nicht Verwenden Sie immer NVARCHAR.Das ist eine sehr gefährliche und oft kostspielige Einstellung/Ansatz.Und es ist nicht besser zu sagen:Niemals „Cursor verwenden“, da sie manchmal das effizienteste Mittel zur Lösung eines bestimmten Problems sind und die übliche Lösung für ein Problem darstellen WHILE Schleife wird fast immer langsamer sein als a richtig fertig Cursor.

Sie sollten den Begriff „immer“ nur dann verwenden, wenn Sie raten, „immer das Beste für die Situation zu tun“.Zugegeben, das lässt sich oft schwer feststellen, insbesondere wenn man versucht, kurzfristige Gewinne in der Entwicklungszeit auszugleichen (Manager:„Wir brauchen diese Funktion – von der Sie bis jetzt – vor einer Woche – noch nichts wussten!“) mit langfristigen Wartungskosten (Manager, der das Team zunächst dazu drängte, ein dreimonatiges Projekt in einem dreiwöchigen Sprint abzuschließen :„Warum haben wir diese Leistungsprobleme?Wie hätten wir X machen können, das keine Flexibilität hat?Wir können uns nicht ein oder zwei Sprints leisten, um das Problem zu beheben.Was können wir in einer Woche erledigen, damit wir uns wieder unseren Prioritäten widmen können?Und wir müssen auf jeden Fall mehr Zeit in das Design investieren, damit das nicht noch einmal passiert!

Zweite: Die Antwort von @gbn geht auf einige sehr wichtige Punkte ein, die bei bestimmten Datenmodellierungsentscheidungen zu berücksichtigen sind, wenn der Weg nicht 100 % klar ist.Aber es gibt noch mehr zu beachten:

  • Größe der Transaktionsprotokolldateien
  • Zeit, die für die Replikation benötigt wird (bei Verwendung der Replikation)
  • Zeit, die zum ETL benötigt wird (wenn ETLing)
  • Zeit, die zum Versenden von Protokollen an ein Remote-System und zur Wiederherstellung benötigt wird (bei Verwendung von Protokollversand)
  • Größe der Backups
  • wie lange es dauert, bis die Sicherung abgeschlossen ist
  • wie lange es dauert, eine Wiederherstellung durchzuführen (das könnte eines Tages wichtig sein ;-)
  • Größe, die für tempdb benötigt wird
  • Leistung von Triggern (für eingefügte und gelöschte Tabellen, die in tempdb gespeichert sind)
  • Leistung der Zeilenversionierung (bei Verwendung von SNAPSHOT ISOLATION, da sich der Versionsspeicher in tempdb befindet)
  • Möglichkeit, neuen Festplattenspeicher zu erhalten, wenn der CFO sagt, dass sie letztes Jahr gerade einmal 1 Million US-Dollar für ein SAN ausgegeben haben und daher keine weiteren 250.000 US-Dollar für zusätzlichen Speicher genehmigen werden
  • Zeitdauer, die für die Ausführung von INSERT- und UPDATE-Vorgängen benötigt wird
  • Dauer der Indexpflege
  • usw. usw. usw.

Platzverschwendung hat eine riesig Kaskadeneffekt auf das gesamte System.Ich habe einen Artikel geschrieben, der explizit auf dieses Thema eingeht: Festplatte ist billig!ORLY? (kostenlose Anmeldung erforderlich;Entschuldigung, ich habe keinen Einfluss auf diese Richtlinie.

Dritte: Während sich einige Antworten fälschlicherweise auf den Aspekt „Dies ist eine kleine App“ konzentrieren und andere zu Recht vorschlagen, „das Angemessene zu verwenden“, hat keine der Antworten dem O.P. eine wirkliche Orientierung gegeben.Ein wichtiges Detail, das in der Frage erwähnt wird, ist, dass es sich um eine Webseite für ihre Schule handelt.Großartig!Daher können wir Folgendes vorschlagen:

  • Felder für Studenten- und/oder Fakultätsnamen sollten vorhanden sein wahrscheinlich Sei NVARCHAR denn mit der Zeit wird es immer wahrscheinlicher, dass an diesen Orten Namen aus anderen Kulturen auftauchen.
  • Aber für Straßenadressen und Städtenamen?Der Zweck der App wurde nicht angegeben (es wäre hilfreich gewesen), es wird jedoch davon ausgegangen, dass sich die Adressdaten, falls vorhanden, nur auf eine bestimmte geografische Region beziehen (d. h.eine einzelne Sprache/Kultur), dann verwenden VARCHAR mit der entsprechenden Codepage (die aus der Sortierung des Feldes bestimmt wird).
  • Wenn ISO-Codes für Bundesstaat und/oder Land gespeichert werden (keine Speicherung erforderlich). INT / TINYINT da ISO-Codes eine feste Länge haben, für Menschen lesbar sind und, nun ja, Standard :) verwenden CHAR(2) für Zwei-Buchstaben-Codes und CHAR(3) bei Verwendung von 3-Buchstaben-Codes.Und erwägen Sie die Verwendung einer binären Sortierung wie z Latin1_General_100_BIN2.
  • Bei der Speicherung von Postleitzahlen (d. h.Postleitzahlen), verwenden VARCHAR da es ein internationaler Standard ist, niemals einen Buchstaben außerhalb von A-Z zu verwenden.Und ja, immer noch im Einsatz VARCHAR Auch wenn nur US-Postleitzahlen und nicht INT gespeichert werden, da Postleitzahlen keine Zahlen, sondern Zeichenfolgen sind und einige von ihnen eine führende „0“ haben.Und erwägen Sie die Verwendung einer binären Sortierung wie z Latin1_General_100_BIN2.
  • Wenn Sie E-Mail-Adressen und/oder URLs speichern, verwenden Sie NVARCHAR da beide nun Unicode-Zeichen enthalten können.
  • und so weiter....

Vierte: Jetzt wo du es hast NVARCHAR Daten nehmen doppelt so viel Platz ein, wie sie für Daten benötigen, die gut hineinpassen VARCHAR („passt gut“ = wird nicht zu „?“) und irgendwie, wie durch Zauberei, wuchs die Anwendung und jetzt gibt es Millionen von Datensätzen in mindestens einem dieser Bereiche, wo am meisten Zeilen sind im Standard-ASCII-Format, einige enthalten jedoch Unicode-Zeichen, sodass Sie diese beibehalten müssen NVARCHAR, Folgendes berücksichtigen:

  1. Wenn Sie SQL Server 2008 - 2016 RTM verwenden Und sich auf der Enterprise Edition befinden ODER wenn Sie SQL Server 2016 SP1 (wodurch die Datenkomprimierung in allen Editionen verfügbar wurde) oder neuer verwenden, können Sie diese aktivieren Datenkompression.Die Datenkomprimierung kann (aber nicht „immer“) Unicode-Daten komprimieren NCHAR Und NVARCHAR Felder.Die bestimmenden Faktoren sind:

    1. NCHAR(1 - 4000) Und NVARCHAR(1 - 4000) Benutze die Standardkomprimierungsschema für Unicode, aber erst ab SQL Server 2008 R2 UND nur für IN ROW-Daten, nicht für OVERFLOW!Dies scheint besser zu sein als der reguläre ROW/PAGE-Komprimierungsalgorithmus.
    2. NVARCHAR(MAX) Und XML (Und ich denke auch VARBINARY(MAX), TEXT, Und NTEXT) Daten, die sich IN ROW befinden (nicht außerhalb der Zeile in LOB- oder OVERFLOW-Seiten), können zumindest PAGE-komprimiert werden, aber nicht ROW komprimiert.Natürlich hängt die PAGE-Komprimierung von der Größe des In-Row-Werts ab:Ich habe mit VARCHAR(MAX) getestet und festgestellt, dass 6000 Zeichen/Byte-Zeilen nicht komprimiert werden konnten, 4000 Zeichen/Byte-Zeilen jedoch schon.
    3. Alle OFF-ROW-Daten, LOB oder OVERLOW = Keine Komprimierung für Sie!
  2. Bei Verwendung von SQL Server 2005 oder 2008–2016 RTM und nicht In der Enterprise Edition können Sie zwei Felder haben:eins VARCHAR und ein NVARCHAR.Angenommen, Sie speichern URLs, die größtenteils nur aus Basis-ASCII-Zeichen (Werte 0–127) bestehen und daher hineinpassen VARCHAR, enthalten aber manchmal Unicode-Zeichen.Ihr Schema kann die folgenden drei 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 Sie nur AUSWÄHLEN aus dem [URL] berechnete Spalte.Beim Einfügen und Aktualisieren bestimmen Sie, welches Feld verwendet werden soll, indem Sie prüfen, ob die Konvertierung den eingehenden Wert ändert, der sein muss NVARCHAR Typ:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. Sie können eingehende Werte per GZIP komprimieren VARBINARY(MAX) und dann auf dem Weg nach draußen entpacken:

    • Für SQL Server 2005–2014:Sie können SQLCLR verwenden. SQL# (eine SQLCLR-Bibliothek, die ich geschrieben habe) ist im Lieferumfang enthalten Util_GZip Und Util_GUnzip in der kostenlosen Version
    • Für SQL Server 2016 und neuer:Sie können das integrierte verwenden COMPRESS Und DECOMPRESS Funktionen, die auch GZip sind.
  4. Wenn Sie SQL Server 2017 oder neuer verwenden, können Sie die Tabelle in einen Clustered Columnstore-Index umwandeln.

  5. Obwohl dies noch keine praktikable Option ist, führt SQL Server 2019 native Unterstützung für UTF-8 ein VARCHAR / CHAR Datentypen.Derzeit gibt es zu viele Fehler, als dass es verwendet werden könnte. Wenn diese jedoch behoben werden, ist dies eine Option für manche 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.

Da Ihre Anwendung klein ist, entstehen bei der Verwendung von nvarchar gegenüber varchar im Wesentlichen keine nennenswerten Kostensteigerungen, und Sie ersparen sich spätere potenzielle Kopfschmerzen, wenn Sie Unicode-Daten speichern müssen.

Allgemein gesagt;Beginnen Sie mit dem teuersten Datentyp, der die geringsten Einschränkungen aufweist. Nehmen Sie es in Produktion.Wenn die Leistung ein Problem darstellt, finden Sie heraus, was tatsächlich darin gespeichert ist nvarchar Säulen.Gibt es dort Charaktere, die nicht hineinpassen würden? varchar?Wenn nicht, wechseln Sie zu Varchar.Versuchen Sie nicht, vorab zu optimieren, bevor Sie wissen, wo der Schmerz liegt.Meine Vermutung ist das Die Wahl zwischen nvarchar/varchar wird Ihre Anwendung nicht verlangsamen in absehbarer Zukunft.Es wird andere Teile der Anwendung geben, in denen Ihnen die Leistungsoptimierung viel mehr bringt Knall fürs Geld.

In den letzten Jahren haben alle unsere Projekte NVARCHAR für alles verwendet, da alle diese Projekte mehrsprachig sind.Importierte Daten aus externen Quellen (z.B.eine ASCII-Datei usw.) wird vor dem Einfügen in die Datenbank in Unicode hochkonvertiert.

Ich habe noch keine leistungsbezogenen Probleme bei den größeren Indizes usw. festgestellt.Die Indizes verbrauchen zwar mehr Speicher, aber Speicher ist günstig.

Unabhängig davon, ob Sie gespeicherte Prozeduren verwenden oder SQL im laufenden Betrieb erstellen, stellen Sie sicher, dass allen Zeichenfolgekonstanten ein N vorangestellt ist (z. B.SET @foo = N'Hello world.';), also ist die Konstante auch Unicode.Dadurch wird eine Konvertierung des String-Typs zur Laufzeit vermieden.

YMMV.

Ich kann diesbezüglich aus Erfahrung sprechen, Vorsicht nvarchar.Sofern Sie es nicht unbedingt benötigen, beeinträchtigt dieser Datenfeldtyp die Leistung größerer Datenbanken.Ich habe eine Datenbank geerbt, deren Leistung und Speicherplatz beeinträchtigt waren.Wir konnten die Größe einer 30 GB großen Datenbank um 70 % reduzieren!Es wurden noch einige andere Modifikationen vorgenommen, um die Leistung zu verbessern, aber ich bin mir sicher, dass dies der Fall ist varchar's hat dabei auch erheblich geholfen.Wenn Ihre Datenbank das Potenzial hat, Tabellen auf mehr als eine Million Datensätze anzuwachsen, lassen Sie die Finger davon nvarchar um jeden Preis.

Ich beschäftige mich bei der Arbeit oft mit dieser Frage:

  • FTP-Feeds mit Inventar und Preisen – Artikelbeschreibungen und anderer Text waren in nvarchar, als varchar einwandfrei funktionierte.Die Konvertierung in Varchar reduzierte die Dateigröße fast um die Hälfte und half wirklich beim Hochladen.

  • Das obige Szenario funktionierte einwandfrei, bis jemand ein Sonderzeichen in die Artikelbeschreibung einfügte (vielleicht eine Marke, ich weiß es nicht mehr).

Ich verwende Nvarchar immer noch nicht jedes Mal anstelle von Varchar.Im Zweifelsfall oder bei Bedarf für Sonderzeichen verwende ich nvarchar.Ich verwende Varchar meistens dann, wenn ich 100 % Kontrolle darüber habe, was das Feld füllt.

Warum wurde UTF-8 in all dieser Diskussion nicht erwähnt?Die Möglichkeit, die gesamte Unicode-Zeichenspanne zu speichern, bedeutet nicht, dass man immer zwei Bytes pro Zeichen (oder „Codepunkt“, um den UNICODE-Begriff zu verwenden) zuweisen muss.Das gesamte ASCII ist UTF-8.Überprüft SQL Server bei VARCHAR()-Feldern, ob der Text strenges ASCII ist (d. h.oberstes Byte Bit Null)?Ich würde es hoffen.

Wenn Sie dann Unicode speichern möchten Und Wenn Sie Kompatibilität mit älteren reinen ASCII-Anwendungen wünschen, würde ich denken, dass die Verwendung von VARCHAR() und UTF-8 das Wundermittel wäre:Es verbraucht nur dann mehr Platz, wenn es nötig ist.

Für diejenigen unter Ihnen, die mit UTF-8 nicht vertraut sind, kann ich es empfehlen eine Grundierung.

Es gibt Ausnahmefälle, in denen Sie den Datentyp bewusst einschränken möchten, um dies sicherzustellen nicht enthalten Zeichen aus einer bestimmten Menge.Ich hatte zum Beispiel ein Szenario, in dem ich den Domänennamen in einer Datenbank speichern musste.Die Internationalisierung für Domänennamen war zu diesem Zeitpunkt noch nicht zuverlässig, daher war es besser, die Eingabe auf der Basisebene zu beschränken und mögliche Probleme zu vermeiden.

Wenn Sie verwenden NVARCHAR nur weil eine gespeicherte Systemprozedur dies erfordert, wobei das häufigste Vorkommen unerklärlich ist sp_executesql, und Ihr dynamisches SQL sehr lang ist, wäre es aus Leistungssicht besser, alle Zeichenfolgenmanipulationen (Verkettung, Ersetzung usw.) in durchzuführen VARCHAR dann Konvertieren des Endergebnisses in NVARCHAR und es in den proc-Parameter einspeisen.Also nein, nicht immer verwenden NVARCHAR!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top