J'ai plusieurs grandes tables avec de nombreuses colonnes NVARCHAR(MAX)
. Cette base de données est uniquement destinée aux États-Unis et je ne pense pas qu'il y ait de caractères ou de lettres étrangers dans l'une des colonnes, donc je voulais examiner:
NVARCHAR
à VARCHAR
, et aussiNVARCHAR(MAX)
semble exagéré.J'essaie également de limiter les conversions implicites.
Quel est un moyen facile de déterminer avant de faire cela si chaque colonne ne contient en effet que des données VARCHAR
et n'aura aucun problème à être convertie à partir de NVARCHAR
?
Cette base de données est réservée aux États-Unis et je ne pense pas qu'il y ait de caractères ou de lettres étrangers dans les colonnes, donc je voulais examiner ... Changer plusieurs de ces colonnes de NVARCHAR à VARCHAR
Avant d'aller plus loin, vous devez rechercher/déterminer les exigences commerciales réelles de ces colonnes. S'il est vrai qu'une ou plusieurs de ces colonnes ne contiennent actuellement aucun caractère qui ne rentrerait pas aussi facilement dans VARCHAR
, cela ne signifie pas que quelqu'un n'essaiera pas d'entrer des caractères Unicode uniquement demain. et que cela serait en dehors de la conception prévue du système. Si les utilisateurs finaux/les vendeurs/les personnes de support/la documentation pensent que des caractères Unicode uniquement peuvent être entrés dans le système, alors le système doit permettre cela, même si personne n'a fait usage de cette fonctionnalité. encore. Si tel est le cas et que vous estimez que cela devrait être changé parce que vous ne pensez pas qu'il soit nécessaire de saisir de tels caractères, vous devez en faire part à un responsable/Product Owner/etc.
De plus, le fait que la base d'utilisateurs prévue se trouve aux États-Unis ne signifie pas que les caractères Unicode uniquement ne seront pas utilisés. Au moins dans les colonnes "nom", colonnes "description", etc., il pourrait facilement y avoir une variété de caractères accentués, ou qui sait quoi. La discussion que vous devriez avoir avec le propriétaire du produit et/ou l'équipe devrait tourner autour de ce qui est requis pour chacune de ces colonnes/points de données.
Je sais par exemple que la longueur maximale des données dans certaines de ces colonnes n'est que d'environ 30 caractères, donc NVARCHAR (MAX) semble exagéré.
Comme pour les points ci-dessus concernant les types de caractères à autoriser dans ces colonnes, vous devez d'abord déterminer le nombre de caractères que le système autorise les utilisateurs à envoyer. Si un champ de description est limité à 500 - 1 000 caractères dans l'interface utilisateur, et d'autres parties du code, et même la documentation (on peut toujours espérer, non?), d'accord, alors absolument oui, NVARCHAR(MAX)
est absolument exagéré. MAIS, si la colonne doit stocker plus de 4000 caractères d'une variété qui n'est pas représentée par une page de codes 8 bits, alors NVARCHAR(MAX)
n'est pas exagéré (bien que vous deviez peut-être envisager une meilleure conception que le stockage trop nombreux dans une seule table). Quoi qu'il en soit, le fait qu'il n'y ait que 30 caractères maximum dans une colonne NVARCHAR(MAX)
particulière est une bonne information à fournir à un Product Owner/team afin qu'une décision plus éclairée puisse être prise concernant le sort de cette colonne. Peut-être qu'un champ qui autorise actuellement 1000 caractères mais a une longueur d'enregistrement maximale de 30 à 50 devrait être mis à jour pour n'autoriser que 75 à 100. Mais cela doit être un effort coordonné.
Cela dit, si vous voulez déterminer s'il y a des caractères dans une colonne NVARCHAR
/NCHAR
/NTEXT
qui ne peuvent pas être convertis en VARCHAR
, vous devez convertir en VARCHAR
en utilisant le _BIN2
variation du classement utilisé pour cette colonne particulière. Par exemple, si une colonne particulière utilise Albanian_100_CI_AS
, vous devez alors spécifier Albanian_100_BIN2
pour le test. La raison d'utiliser un _BIN2
le classement est que les classements non binaires ne trouveront que les cas où il y a au moins un caractère qui n'a aucun mappage du tout dans la page de code et est donc converti en ?
. Mais, les classements non binaires n'attrapent pas les instances où il y a des caractères qui n'ont pas de mappage direct dans la page de code, mais ont plutôt un mappage "le mieux adapté". Par exemple, le caractère exposant 2, ²
, a un mappage direct dans la page de code 1252, donc certainement pas de problème. D'un autre côté, il n'a pas de mappage direct dans la page de codes 1250 (utilisée par les classements albanais), mais il a un mappage "le mieux adapté" qui le convertit en un 2
. Le problème avec le classement non binaire est que 2
équivaudra à ²
et il ne sera donc pas enregistré comme ligne qui ne peut pas être convertie en VARCHAR
. Par exemple:
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE French_100_CI_AS); -- Code Page 1252
-- ²
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS); -- Code Page 1250
-- 2
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS)
WHERE N'²' <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_CI_AS));
-- (no rows returned)
SELECT CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_BIN2)
WHERE N'²' <> CONVERT(NVARCHAR(MAX),
CONVERT(VARCHAR(MAX), N'²' COLLATE Albanian_100_BIN2));
-- 2
Idéalement, vous devez reconvertir en NVARCHAR
explicitement pour que le code soit clair sur ce qu'il fait, bien que ne pas le faire se reconvertira implicitement en NVARCHAR
, donc le comportement est le même dans les deux cas.
Si plusieurs de ces colonnes sont déjà dans NVARCHAR, ce n'est pas nécessairement là que j'irais pour les changer. C'est parce que le code ASCII est de toute façon au début de la page de code UNICODE. D'un autre côté, NVARCHAR (MAX) ressemble définitivement à une (très) mauvaise conception. Essayez d'obtenir un script par colonne ce qui est le MAX réel et le changer à partir de là. BTW il se pourrait que certains de ces NVARCHAR (MAX) soient en fait .... CHAR (5); si sa longueur est inférieure à 10 environ, alors une chaîne de longueur fixe serait préférable. Optez d'abord pour les petits et vérifiez les clés (vous voulez également économiser sur le temps de jointure, correct?)
Si quelque chose a un maximum de 30, c'est probablement le maximum requis par l'application. Faites-en NVARCHAR (100) (s'il s'agit d'un champ de texte libre; quelqu'un pourrait entrer un texte français) et vous pouvez être sûr que c'est la bonne longueur.
BTW, si c'est la façon dont la base de données est conçue, jetez également un œil aux champs int/numériques. Pourquoi utiliser BIGINT alors qu'une petite ou même une minuscule pourrait être assez bonne?
Je crois que vous recherchez une instruction select qui vous trouverait les chaînes qui ne seraient pas prises en charge dans ASCII (VARCHAR), correct?
La réponse référencée ci-dessous fournit une telle déclaration (avec un exemple de structure de tableau). Ce que fait cette instruction, c'est comparer la valeur que vous avez stockée en tant que NVARCHAR (Unicode) avec la même valeur transtypée que VARCHAR (ASCII). Si la requête ne renvoie rien, vous pouvez convertir. Si une ligne contient une colonne avec une valeur différente dans stockée en tant que VARCHAR, elle sera retournée.
J'ai copié l'exemple de l'autre réponse ci-dessous:
SELECT NAME, ADDRESS, DESCRIPTION
FROM DBO.USERS
WHERE NAME != CAST(NAME AS VARCHAR(4000))
OR ADDRESS != CAST(ADDRESS AS VARCHAR(4000))
OR DESCRIPTION != CAST(DESCRIPTION AS VARCHAR(4000))
Peut-être une modification du post d'equipe9 où vous avez à la dernière étape converti les valeurs en varbinary? Quelque chose comme
CAST (NOM COMME binaire (max))! = CAST (CAST (NOM COMME VARCHAR (4000)) AS binaire (max))
Non testé, je devrais ajouter, je pense juste à haute voix ...
Une autre option pourrait être d'activer la compression des lignes, qui vient également (à partir de 2008R2) avec la compression Unicode. De cette façon, vous payez beaucoup moins pour les personnages "ordinaires".