Ich zögere, hier noch eine weitere Antwort hinzuzufügen, da es bereits einige gibt, aber einige Punkte müssen gemacht werden, die entweder nicht oder nicht klar gemacht wurden.
Erstens: Do nicht immer verwenden NVARCHAR
. Das ist eine sehr gefährliche und oft kostspielige Einstellung. Und es ist nicht besser zu sagen, " Verwenden Sie niemals Cursor", da sie manchmal das effizienteste Mittel zur Lösung eines bestimmten Problems sind und die übliche Umgehung einer WHILE
Schleife fast immer langsamer ist als ein ordnungsgemäß durchgeführter Cursor.
Sie sollten den Begriff "immer" nur verwenden, wenn Sie raten, "immer das zu tun, was für die Situation am besten ist". Zugegeben, das ist oft schwer zu bestimmen, insbesondere wenn versucht wird, kurzfristige Gewinne in der Entwicklungszeit (Manager: "Wir brauchen diese Funktion - von der Sie bis jetzt noch nichts wussten - vor einer Woche!") Mit Long in Einklang zu bringen -term Wartungskosten (Manager, der das Team anfangs unter Druck setzte, ein dreimonatiges Projekt in einem dreiwöchigen Sprint abzuschließen: "Warum haben wir diese Leistungsprobleme? Wie hätten wir möglicherweise X machen können, das keine Flexibilität hat? Wir können es uns nicht leisten." ein oder zwei Sprints, um dies zu beheben. Was können wir in einer Woche erledigen, damit wir zu unseren vorrangigen Elementen zurückkehren können? Und wir müssen definitiv mehr Zeit im Design verbringen, damit dies nicht immer passiert! ").
Zweitens: Die Antwort von @ gbn berührt einige sehr wichtige Punkte, die bei bestimmten Datenmodellierungsentscheidungen zu berücksichtigen sind, wenn der Pfad nicht 100% klar ist. Aber es gibt noch mehr zu beachten:
- Größe der Transaktionsprotokolldateien
- Zeit für die Replikation (bei Verwendung der Replikation)
- Zeit, die für ETL benötigt wird (wenn ETLing)
- Zeit, die benötigt wird, um Protokolle an ein Remote-System zu senden und wiederherzustellen (wenn Sie den Protokollversand verwenden)
- Größe der Backups
- Zeitdauer, die zum Abschließen der Sicherung benötigt wird
- Zeitdauer für eine Wiederherstellung (dies könnte eines Tages wichtig sein ;-)
- Größe für Tempdb benötigt
- 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 Speicherplatz zu erhalten, wenn der CFO angibt, dass er letztes Jahr nur 1 Million US-Dollar für ein SAN ausgegeben hat und daher keine weiteren 250.000 US-Dollar für zusätzlichen Speicher autorisiert
- Zeitdauer für INSERT- und UPDATE-Operationen
- Zeitdauer für die Indexpflege
- usw. usw. usw. usw.
Platzverschwendung hat einen enormen Kaskadeneffekt auf das gesamte System. Ich habe einen Artikel geschrieben, der ausführlich auf dieses Thema eingeht : Disk Is Cheap! ORLY? (Kostenlose Registrierung erforderlich; Entschuldigung, ich kontrolliere diese Richtlinie nicht).
Drittens: Während sich einige Antworten fälschlicherweise auf den Aspekt "Dies ist eine kleine App" konzentrieren und andere zu Recht vorschlagen, "das zu verwenden, was angemessen ist", hat keine der Antworten dem OP eine echte Anleitung gegeben. Ein wichtiges Detail, das in der Frage erwähnt wird ist, dass dies eine Webseite für ihre Schule ist. Toll! Wir können also Folgendes vorschlagen:
- Felder für Studenten- und / oder Fakultätsnamen sollten wahrscheinlich vorhanden sein,
NVARCHAR
da es mit der Zeit immer wahrscheinlicher wird, dass Namen aus anderen Kulturen an diesen Orten auftauchen.
- Aber für Adresse und Städtenamen? Der Zweck der App wurde nicht angegeben (es wäre hilfreich gewesen), aber unter der Annahme, dass sich die Adressdatensätze, falls vorhanden, nur auf eine bestimmte geografische Region (dh eine einzelne Sprache / Kultur) beziehen, dann verwenden
VARCHAR
mit der entsprechenden Codepage (welche) verwendet wird aus der Sortierung des Feldes bestimmt).
- Wenn Sie ISO-Codes für Bundesstaaten und / oder Länder speichern (keine Notwendigkeit zum Speichern
INT
/ TINYINT
da ISO-Codes eine feste Länge haben, für Menschen lesbar und gut standardisiert sind :), verwenden Sie sie CHAR(2)
für zwei Buchstabencodes und CHAR(3)
wenn Sie 3 Buchstabencodes verwenden. Und erwägen Sie die Verwendung einer binären Kollatierung wie z Latin1_General_100_BIN2
.
- Wenn Sie Postleitzahlen (dh Postleitzahlen) speichern, verwenden
VARCHAR
Sie diese , da es ein internationaler Standard ist, niemals Buchstaben außerhalb von AZ zu verwenden. Und ja, verwenden Sie es VARCHAR
auch dann, wenn Sie nur US-Postleitzahlen und nicht INT speichern, da Postleitzahlen keine Zahlen sind, sondern Zeichenfolgen, und einige von ihnen haben eine führende "0". Und erwägen Sie die Verwendung einer binären Kollatierung wie z Latin1_General_100_BIN2
.
- Wenn Sie E-Mail-Adressen und / oder URLs speichern, verwenden Sie diese Option,
NVARCHAR
da beide jetzt Unicode-Zeichen enthalten können.
- und so weiter....
Viertens: Jetzt, da Sie NVARCHAR
Daten haben, die doppelt so viel Speicherplatz beanspruchen wie für Daten, die gut passen VARCHAR
("passt gut" = verwandelt sich nicht in "?"), Wuchs die Anwendung irgendwie wie von Zauberhand und jetzt gibt es Millionen von Datensätzen in mindestens einem dieser Felder, in denen die meisten Zeilen Standard-ASCII sind, aber einige Unicode-Zeichen enthalten, sodass Sie NVARCHAR
Folgendes beachten müssen:
Wenn Sie SQL Server 2008 - 2016 RTM verwenden und Enterprise Edition verwenden, ODER wenn Sie SQL Server 2016 SP1 (mit dem die Datenkomprimierung in allen Editionen verfügbar gemacht wurde) oder eine neuere Version verwenden, können Sie die Datenkomprimierung aktivieren . Die Datenkomprimierung kann (aber nicht "immer") Unicode-Daten in NCHAR
und NVARCHAR
Felder komprimieren . Die bestimmenden Faktoren sind:
NCHAR(1 - 4000)
und NVARCHAR(1 - 4000)
verwenden Sie das Standardkomprimierungsschema für Unicode , jedoch nur 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.
NVARCHAR(MAX)
und XML
(und ich denke auch VARBINARY(MAX)
, TEXT
und NTEXT
) Daten, die IN ROW sind (nicht außerhalb der Zeile in LOB- oder OVERFLOW-Seiten), können mindestens PAGE-komprimiert, aber nicht ROW-komprimiert werden. 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, 4000 Zeichen / Byte-Zeilen jedoch.
- Alle OFF ROW-Daten, LOB oder OVERLOW = Keine Komprimierung für Sie!
Wenn Sie SQL Server 2005 oder 2008 - 2016 RTM und nicht Enterprise Edition verwenden, können Sie zwei Felder verwenden: eines VARCHAR
und eines NVARCHAR
. Angenommen, Sie speichern URLs, bei denen es sich größtenteils um ASCII-Basiszeichen (Werte 0 bis 127) handelt und die daher in VARCHAR
Unicode-Zeichen passen , diese jedoch manchmal haben. 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 wählen Sie nur aus der [URL]
berechneten Spalte. Zum Einfügen und Aktualisieren bestimmen Sie, welches Feld verwendet werden soll, indem Sie prüfen, ob durch die Konvertierung der eingehende Wert geändert wird, der vom NVARCHAR
Typ sein muss:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
Sie können eingehende Werte in GZIP VARBINARY(MAX)
eingeben und 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) enthält Util_GZip und Util_GUnzip in der kostenlosen Version
- Für SQL Server 2016 und höher: Sie können die integrierten Funktionen
COMPRESS
und DECOMPRESS
Funktionen verwenden, die auch GZip sind.
Wenn Sie SQL Server 2017 oder höher verwenden, können Sie die Tabelle zu einem Clustered Columnstore-Index machen.
Obwohl dies noch keine praktikable Option ist, führt SQL Server 2019 die native Unterstützung für UTF-8 in VARCHAR
/ CHAR
datatypes ein. Derzeit gibt es zu viele Fehler, als dass sie verwendet werden könnten. Wenn sie jedoch behoben sind, ist dies für einige Szenarien eine Option . Eine detaillierte Analyse dieser neuen Funktion finden Sie in meinem Beitrag " Native UTF-8-Unterstützung in SQL Server 2019: Retter oder falscher Prophet? ".