Quand `nvarchar / nchar` va être utilisé avec SQL Server 2019?

11

Avec SQL Server 2019 Microsoft de soutien UTF-8 pour CHARet VARCHARles types de données et dit:

Cette fonctionnalité peut permettre des économies de stockage importantes, selon le jeu de caractères utilisé. Par exemple, la modification d'un type de données de colonne existant avec des chaînes ASCII de NCHAR (10) à CHAR (10) à l'aide d'un classement activé UTF-8, se traduit par une réduction de près de 50% des exigences de stockage. Cette réduction est due au fait que NCHAR (10) nécessite 22 octets pour le stockage, tandis que CHAR (10) nécessite 12 octets pour la même chaîne Unicode.

UTF-8 semble soutenir chaque script, donc en gros , nous pouvons commencer à stocker des données Unicode dans varcharet charcolonnes. Et comme indiqué dans la documentation, cela peut réduire la taille des tables et des index, et à partir de là, nous pouvons obtenir des performances encore meilleures, car une plus petite quantité de données est lue.

Je me demande si cela signifie que nous pouvons arrêter d'utiliser nvarcharet des ncharcolonnes qui implémentent UTF-16?

Quelqu'un peut-il pointer un scénario et une raison, pour ne pas utiliser les types de données char avec l' UTFencodage et continuer à utiliser ceux n-chars?

gotqn
la source
Pourquoi ne le testez-vous pas et n'en faites-vous pas rapport? Faites-nous également savoir combien d’efforts vous avez consacrés à la conversion de nvarchar en varchar - combien de temps les tables alter ont pris, combien de temps vous avez passé à tester et quels problèmes vous avez rencontrés.
Colin 't Hart
@ Colin'tHart S'il n'y a pas de problèmes ou de considérations connus, je prévois de migrer les données car je pense que la lecture de moins de données entraînera de meilleures performances pour le système. À propos de la conversion - cela prendra du temps, bien sûr, surtout si vous avez des index avec la colonne donnée - ils doivent être reconstruits, mais je pense que cela portera ses fruits. Bien sûr, je vais bientôt tester l'impact sur les performances, à la recherche de tout problème qui rendrait la migration inutile.
gotqn
Notez que SQL Server prend en charge la compression Unicode pour les colonnes NVarchar lors de l'utilisation de la compression PAGE ou ROW. docs.microsoft.com/en-us/sql/relational-databases/…
David Browne - Microsoft
1
Il convient de noter que même si l'UTF-8 peut économiser de l'espace si vous stockez des "données de type ASCII", ce n'est pas une compression en soi et ne doit pas être confondu en tant que tel. Par exemple, si vous stockez principalement des noms chinois dans une base de données, il serait plus difficile d'utiliser des CHARtypes UTF-8 que des types Unicode (avec ou sans compression, car les données doivent finalement être décompressées pour être traitées). Considérez également que le type de chaîne natif de Windows est Unicode, donc les chaînes UTF-8 doivent souvent être décodées. Les compromis impliqués signifient qu'il est peu probable que les Ntypes soient retirés de si tôt.
Jeroen Mostert du
1
La «killer app» n ° 1 pour UTF-8 CHARest probablement SQL Server sous Linux, si le moteur obtient un support natif pour le traitement des chaînes directement en UTF-8 - ici UTF-8 est le jeu de caractères «natif» (plus ou moins) et garder les chaînes autour comme UTF-16 est l'alternative moins efficace. CHARBien sûr, cela ne fera pas de mal de l'utiliser sur Windows dans des endroits où vous l'utilisez déjà , car les classements restreignant les caractères pouvant être stockés n'ont jamais été attrayants.
Jeroen Mostert

Réponses:

6

cela peut réduire la taille des tables et des index (emphase ajoutée)

Réduction de la taille est seulement possible si la plupart des personnages sont essentiellement [space], 0 - 9, A - Z, a - zet certains signes de ponctuation de base. En dehors de cet ensemble spécifique de caractères (en termes d'utilisation pratique, valeurs ASCII standard 32 - 126), vous serez au mieux égal en taille à NVARCHAR/ UTF-16, ou dans de nombreux cas plus grand.

Je prévois de migrer les données car je pense que la lecture de moins de données entraînera de meilleures performances pour le système.

Faites attention. L'UTF-8 n'est pas un commutateur magique «tout réparer». Toutes choses étant égales par ailleurs, oui, lire moins améliore les performances. Mais ici "toutes les autres choses" ne sont pas égales. Même lorsque vous ne stockez que des caractères ASCII standard (ce qui signifie que tous les caractères font 1 octet, ce qui nécessite donc la moitié de l'espace par rapport au stockage NVARCHAR), il existe une légère pénalité de performance pour l'utilisation de l'UTF-8. Je crois que le problème est dû au fait que l'UTF-8 est un codage de longueur variable, ce qui signifie que chaque octet doit être interprété tel qu'il est lu afin de savoir s'il s'agit d'un caractère complet ou si l'octet suivant en fait partie. Cela signifie que toutes les opérations de chaîne doivent commencer au début et se poursuivre octet par octet. D'autre part,NVARCHAR / UTF-16 est toujours de 2 octets (même les caractères supplémentaires sont composés de deux points de code de 2 octets), de sorte que tout peut être lu par blocs de 2 octets.

Lors de mes tests, même avec uniquement des caractères ASCII standard, le stockage des données au format UTF-8 n'a pas permis de gagner du temps, mais était nettement pire pour le temps CPU. Et c'était sans compression de données, donc au moins il y avait moins d'espace disque utilisé. Mais, lors de l'utilisation de la compression, l'espace requis pour UTF-8 n'était que de 1% à 1,5% plus petit. Donc, effectivement, aucune économie d'espace, mais un temps processeur plus long pour UTF-8.

Les choses deviennent plus compliquées lors de l'utilisation NVARCHAR(MAX)car la compression Unicode ne fonctionne pas avec ce type de données, même si la valeur est suffisamment petite pour être stockée en ligne. Mais, si les données sont suffisamment petites, elles devraient toujours bénéficier de la compression de lignes ou de pages (auquel cas elles deviennent en fait plus rapides que UTF-8). Cependant, les données hors ligne ne peuvent utiliser aucune compression. Pourtant, faire de la table un index de colonnes en cluster réduit considérablement la taille de NVARCHAR(MAX)(même si elle est toujours légèrement plus grande que UTF-8 lors de l'utilisation de l'index de colonnes en cluster).

Quelqu'un peut-il pointer un scénario et une raison, ne pas utiliser les types de données char avec l'encodage UTF

Absolument. En fait, je ne trouve pas vraiment de raison impérieuse de l'utiliser dans la plupart des cas. Le seul scénario qui bénéficie vraiment de l'UTF-8 est:

  1. Les données sont principalement ASCII standard (valeurs 0 - 127)
  2. Il doit être Unicode car il peut être nécessaire de stocker une plage de caractères plus large que celle disponible sur n'importe quelle page de code 8 bits (c.-à-d. VARCHAR)
  3. La plupart des données sont stockées hors ligne (donc la compression de page ne fonctionne même pas)
  4. Vous disposez de suffisamment de données dont vous avez besoin / souhaitez réduire la taille pour des raisons autres que les performances de requête (par exemple, réduire la taille de la sauvegarde, réduire le temps requis pour la sauvegarde / restauration, etc.)
  5. Vous ne pouvez pas utiliser Clustered Columnstore Index (peut-être que l'utilisation de la table aggrave les performances dans ce cas?)

Mes tests montrent que dans presque tous les cas, NVARCHAR était plus rapide, surtout quand il y avait plus de données. En fait, 21 000 lignes avec une moyenne de 5 000 caractères par ligne nécessitaient 165 Mo pour UTF-8 et 236 Mo pour NVARCHARnon compressé. Et pourtant, il NVARCHARétait 2x plus rapide en temps écoulé, et au moins 2x plus rapide (parfois plus) en temps CPU. Pourtant, il occupait 71 Mo de plus sur le disque.

En dehors de cela, je ne recommanderais toujours pas d'utiliser UTF-8, au moins à partir de CTP 2, en raison d'une variété de bogues que j'ai trouvés dans cette fonctionnalité.

Pour une analyse détaillée de cette nouvelle fonctionnalité, y compris une explication des différences entre UTF-16 et UTF-8, et une liste de ces bogues, veuillez consulter mon article:

Prise en charge native UTF-8 dans SQL Server 2019: Sauveur ou faux prophète?

Solomon Rutzky
la source
12

La prise en charge UTF-8 vous offre un nouvel ensemble d'options. Les économies d'espace potentielles (sans compression de lignes ou de pages ) sont une considération, mais le choix du type et du codage devrait probablement être principalement basé sur les exigences réelles de comparaison, de tri, d' importation et d'exportation de données .

Vous devrez peut-être modifier plus que vous ne le pensez, car par exemple, un nchar(1)type fournit deux octets de stockage. Cela suffit pour stocker n'importe quel caractère dans BMP (points de code 000000 à 00FFFF). Certains des caractères de cette plage seraient codés avec seulement 1 octet en UTF-8 tandis que d'autres nécessiteraient 2 ou même 3 octets (voir ce tableau de comparaison pour plus de détails). Par conséquent, assurer la couverture du même ensemble de caractères en UTF-8 nécessiterait char(3).

Par exemple:

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);

donne l'erreur familière:

Msg 8152, niveau 16, état 30, ligne xxx La
chaîne ou les données binaires seraient tronquées.

Ou si l'indicateur de trace 460 est actif:

Msg 2628, niveau 16, état 1, ligne xxx La
chaîne ou les données binaires seraient tronquées dans le tableau '@T', colonne 'UTF8'. Valeur tronquée: ''.

Étendre la colonne UTF8 char(2)ou varchar(2)résoudre l'erreur pour NCHAR(911):

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);

Cependant, si c'était par exemple NCHAR(8364), vous auriez besoin de développer la colonne plus loin, à char(3)ou varchar(3).

Notez également que les classements UTF-8 utilisent tous des caractères supplémentaires, donc ne fonctionneront pas avec la réplication.

Mis à part toute autre chose, le support UTF-8 n'est que dans l'aperçu pour le moment, donc pas disponible pour une utilisation en production.

Paul White 9
la source