J'hésite à ajouter une autre réponse ici car il y en a déjà pas mal, mais il faut faire quelques remarques qui n'ont pas été faites ou qui n'ont pas été faites clairement.
Premièrement: ne pas toujours utiliser NVARCHAR
. C'est une attitude / approche très dangereuse et souvent coûteuse. Et il ne vaut pas mieux dire « N'utilisez jamais de curseurs» car ils sont parfois le moyen le plus efficace de résoudre un problème particulier, et la solution habituelle pour faire une WHILE
boucle sera presque toujours plus lente qu'un curseur correctement fait.
La seule fois où vous devriez utiliser le terme "toujours" est lorsque vous conseillez de "toujours faire ce qui est le mieux pour la situation". Certes, cela est souvent difficile à déterminer, en particulier lorsque vous essayez d'équilibrer les gains à court terme en temps de développement (gestionnaire: "nous avons besoin de cette fonctionnalité - que vous ne connaissiez pas jusqu'à présent - il y a une semaine!") Avec une longue - les coûts de maintenance à long terme (gestionnaire qui a initialement fait pression sur l'équipe pour terminer un projet de 3 mois dans un sprint de 3 semaines: "pourquoi avons-nous ces problèmes de performance? Comment aurions-nous pu faire X qui n'a pas de flexibilité? Nous ne pouvons pas nous permettre un sprint ou deux pour résoudre ce problème. Que pouvons-nous faire en une semaine pour revenir à nos éléments prioritaires? Et nous devons certainement consacrer plus de temps à la conception afin que cela ne se reproduise pas! ").
Deuxièmement: @ gbn répond à certains points très importants à prendre en compte lors de certaines décisions de modélisation de données lorsque le chemin n'est pas clair à 100%. Mais il y a encore plus à considérer:
- taille des fichiers journaux des transactions
- temps de réplication (si vous utilisez la réplication)
- temps nécessaire à ETL (si ETLing)
- temps nécessaire pour envoyer les journaux à un système distant et les restaurer (si vous utilisez l'envoi de journaux)
- taille des sauvegardes
- durée nécessaire pour terminer la sauvegarde
- temps nécessaire pour effectuer une restauration (cela peut être important un jour ;-)
- taille nécessaire pour tempdb
- performances des déclencheurs (pour les tables insérées et supprimées qui sont stockées dans tempdb)
- performances du versionnage des lignes (si vous utilisez SNAPSHOT ISOLATION, car le magasin de versions est dans tempdb)
- possibilité d'obtenir un nouvel espace disque lorsque le directeur financier dit qu'il vient de dépenser 1 million de dollars sur un SAN l'année dernière et qu'il n'autorisera donc pas 250 000 $ supplémentaires pour du stockage supplémentaire
- durée nécessaire aux opérations INSERT et UPDATE
- durée nécessaire à la maintenance de l'index
- etc, etc, etc.
Le gaspillage d'espace a un énorme effet de cascade sur l'ensemble du système. J'ai écrit un article expliquant en détail ce sujet: le disque est bon marché! ORLY? (inscription gratuite requise; désolé, je ne contrôle pas cette politique).
Troisièmement: bien que certaines réponses se concentrent incorrectement sur l'aspect "il s'agit d'une petite application" et que certaines suggèrent correctement "d'utiliser ce qui est approprié", aucune des réponses n'a fourni de véritables orientations au PO. Un détail important mentionné dans la question c'est que c'est une page web pour leur école. Génial! Nous pouvons donc suggérer que:
- Les champs pour les noms des étudiants et / ou des professeurs doivent probablement l' être
NVARCHAR
car, avec le temps, il est de plus en plus probable que des noms d'autres cultures apparaîtront à ces endroits.
- Mais pour l'adresse et les noms de ville? Le but de l'application n'a pas été indiqué (cela aurait été utile) mais en supposant que les enregistrements d'adresse, le cas échéant, ne concernent qu'une région géographique particulière (c'est-à-dire une seule langue / culture), puis utilisez-la
VARCHAR
avec la page de code appropriée (qui est déterminé à partir du classement du champ).
- Si vous stockez des codes ISO d' État et / ou de pays (pas besoin de les stocker
INT
/ TINYINT
puisque les codes ISO sont de longueur fixe, lisibles par l'homme et bien, standard :) utilisez CHAR(2)
pour les codes à deux lettres et CHAR(3)
si vous utilisez des codes à 3 lettres. Et pensez à utiliser un classement binaire tel queLatin1_General_100_BIN2
.
- Si vous stockez des codes postaux (c'est-à-dire des codes postaux), utilisez,
VARCHAR
car il s'agit d'une norme internationale de ne jamais utiliser de lettre en dehors de AZ. Et oui, utilisez toujours VARCHAR
même si vous ne stockez que des codes postaux américains et non INT, car les codes postaux ne sont pas des nombres, ce sont des chaînes et certains d'entre eux ont un "0" en tête. Et pensez à utiliser un classement binaire tel queLatin1_General_100_BIN2
.
- Si vous stockez des adresses e-mail et / ou des URL, utilisez-les
NVARCHAR
car les deux peuvent désormais contenir des caractères Unicode.
- etc....
Quatrièmement: Maintenant que les NVARCHAR
données occupent deux fois plus d'espace que nécessaire pour les données qui s'intègrent bien VARCHAR
("s'intègre bien" = ne se transforme pas en "?") Et, d'une manière ou d'une autre, comme par magie, l'application s'est développée et maintenant il y a des millions d'enregistrements dans au moins un de ces champs où la plupart des lignes sont en ASCII standard mais certaines contiennent des caractères Unicode, vous devez donc les conserver NVARCHAR
, tenez compte des points suivants:
Si vous utilisez SQL Server 2008-2016 RTM et que vous êtes sur Enterprise Edition, OU si vous utilisez SQL Server 2016 SP1 (qui a rendu la compression de données disponible dans toutes les éditions) ou une version plus récente, vous pouvez activer la compression de données . La compression des données peut (mais pas "toujours") compresser les données Unicode dans les champs NCHAR
et NVARCHAR
. Les facteurs déterminants sont:
NCHAR(1 - 4000)
et NVARCHAR(1 - 4000)
utiliser le schéma de compression standard pour Unicode , mais uniquement à partir de SQL Server 2008 R2, ET uniquement pour les données IN ROW, pas OVERFLOW! Cela semble être meilleur que l'algorithme de compression ROW / PAGE habituel.
NVARCHAR(MAX)
et XML
(et je suppose aussi VARBINARY(MAX)
, TEXT
et NTEXT
) les données IN ROW (pas hors ligne dans les pages LOB ou OVERFLOW) peuvent au moins être compressées en PAGE, mais pas en ROW. Bien sûr, la compression de PAGE dépend de la taille de la valeur en ligne: j'ai testé avec VARCHAR (MAX) et j'ai vu que 6000 lignes de caractères / octets ne se comprimeraient pas, mais 4000 lignes de caractères / octets le faisaient.
- Toutes les données OFF ROW, LOB ou OVERLOW = Aucune compression pour vous!
Si vous utilisez SQL Server 2005 ou 2008-2016 RTM et non sur Enterprise Edition, vous pouvez avoir deux champs: un VARCHAR
et un NVARCHAR
. Par exemple, supposons que vous stockiez des URL qui sont pour la plupart toutes des caractères ASCII de base (valeurs 0 - 127) et qui, par conséquent, tiennent dans VARCHAR
, mais ont parfois des caractères Unicode. Votre schéma peut inclure les 3 champs suivants:
...
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))
);
Dans ce modèle, vous ne sélectionnez que dans la [URL]
colonne calculée. Pour l'insertion et la mise à jour, vous déterminez le champ à utiliser en voyant si la conversion modifie la valeur entrante, qui doit être de NVARCHAR
type:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
Vous pouvez GZIP les valeurs entrantes VARBINARY(MAX)
puis décompressez à la sortie:
- Pour SQL Server 2005-2014: vous pouvez utiliser SQLCLR. SQL # (une bibliothèque SQLCLR que j'ai écrite) est livré avec Util_GZip et Util_GUnzip dans la version gratuite
- Pour SQL Server 2016 et plus récent: vous pouvez utiliser les fonctions intégrées
COMPRESS
et DECOMPRESS
, qui sont également GZip.
Si vous utilisez SQL Server 2017 ou une version plus récente, vous pouvez envisager de faire de la table un index de colonnes en cluster.
Bien que ce n'est pas une option viable encore, SQL Server 2019 introduit un support natif pour UTF-8 dans VARCHAR
/ CHAR
types de données. Il y a actuellement trop de bogues avec lui pour qu'il soit utilisé, mais s'ils sont corrigés, alors c'est une option pour certains scénarios. Veuillez consulter mon article, " Prise en charge native UTF-8 dans SQL Server 2019: Sauveur ou faux prophète? ", Pour une analyse détaillée de cette nouvelle fonctionnalité.