web-dev-qa-db-fra.com

Pourquoi XML prend-il plus de stockage que Varchar (Max)?

Nous avons de grandes tables stockant des données XML comme Varchar (Max). Les données sont à titre de référence/historique, il n'est pas interrogé. Sur la base de ce que j'ai lu, stocker en tant que DataType XML au lieu de Varchar (MAX) devrait entraîner des économies d'espace, mais mes tests montrent le contraire. Voir ci-dessous, où la taille de T1_XML est plus petite que T1_NVARCHARMAX, mais plus grande que T1_VARCHARMAX.

set nocount on;

drop table t1_XML;
drop table t1_VARCHARMAX;
drop table t1_NVARCHARMAX;

create table t1_XML(col1 int identity primary key, col2 XML);
create table t1_VARCHARMAX(col1 int identity primary key, col2 varchar(max));
create table t1_NVARCHARMAX(col1 int identity primary key, col2 nvarchar(max));

go

declare @xml XML = '<root><element1>test</element1><element2>test</element2><element3>test</element3><element4>test</element4><element5>test</element5></root>'
    , @x int = 1;

while @x <= 10000
begin
    begin tran

    insert into dbo.t1_XML (col2) values (@xml);
    insert into dbo.t1_VARCHARMAX (col2) values (cast(@xml as varchar(max)));
    insert into dbo.t1_NVARCHARMAX (col2) values (cast(@xml as varchar(max)));

    commit tran

    set @x += 1;
end

exec sp_spaceused 'dbo.t1_XML';
exec sp_spaceused 'dbo.t1_VARCHARMAX';
exec sp_spaceused 'dbo.t1_NVARCHARMAX';

enter image description here

3
Greg

Il y a deux choses à savoir sur le type XML DataType expliquant ensemble ce que vous vivez:

  1. Comme indiqué dans @ Evancarroll's Reshant , le type de données XML est optimisé. Signification, plutôt que répéter les noms d'éléments et d'attributs (qui sont généralement répétés un peu et constituent une grande partie de la raison pour laquelle tant de personnes, parfois à juste titre, se plaignent des documents XML étant si encombrants), une liste de dictionnaire/recherche est créée pour Conservez chaque nom unique une fois, compte tenu d'un identifiant numérique et que l'ID est utilisé pour remplir la structure du document. C'est pourquoi le type de données XML est souvent un meilleur moyen de stocker des documents XML.
  2. De plus, le type de données XML utilise UTF-16 (Little Endian) pour stocker des valeurs de chaîne (noms d'élément et d'attribut ainsi que tout contenu de chaîne réel). Ce type de données n'utilise pas de compression, de sorte que les chaînes sont essentiellement 2 ou 4 octets par caractère, la plupart des caractères étant la variété de 2 octets.

En regardant le document XML de test particulier que vous utilisez et le type de données VARCHAR (1 à 2 octets par caractère, le plus souvent la variété de 1 octet), nous pouvons maintenant expliquer ce que vous voyez comme résultat de la suite de :

  1. Chacun de vos éléments (root, element1, etc.) ne sont utilisés qu'une seule fois, les seules économies consistant à placer les noms dans la liste de recherche sont de couper la taille exactement à moitié. Mais, le type XML utilise UTF-16, de sorte que la taille de chaque chaîne est deux fois plus autant, annulant les économies de déplacement des noms d'élément dans la liste de recherche. À ce stade, s'il ne regarde que la structure du document (c'est-à-dire des noms d'éléments), il ne devrait y avoir aucune différence entre le type XML et la version VARCHAR.
  2. Mais, la teneur en chaîne dans chaque élément (c'est-à-dire test) prend deux fois le nombre d'octets: 8 octets dans XML par opposition à 4 octets dans VARCHAR. Étant donné qu'il y a 5 cas de "test" par chaque rangée, c'est 20 octets supplémentaires par ligne pour le type XML. À 10 000 rangs, c'est 200 000 octets supplémentaires de la différence de 600 000 octets. Le reste est une surcharge interne du type XML et la page de page supplémentaire du nombre supplémentaire de données requises pour stocker le même nombre de lignes dues à chaque ligne étant légèrement plus grande.

Pour mieux illustrer ce comportement, examinez les deux variations suivantes des données XML: le premier étant exactement le même XML que dans la question, et le second étant presque identique, mais avec tous les éléments étant le même nom. Dans la deuxième version, tous les noms d'élément sont "Element1" de sorte qu'ils ont la même longueur que chaque élément de la version originale. Cela donne des résultats dans la longueur de données VARCHAR étant la même chose dans les deux cas. Mais les noms d'éléments étant les mêmes dans la deuxième version permettent aux optimisations internes d'être plus perceptibles.

-- Original XML (unique element names -- "element1", "element2", ... "elementN"):
DECLARE @xml XML =  '<root><element1>test</element1><element2>test</element2>
<element3>test</element3><element4>test</element4><element5>test</element5></root>';
SELECT DATALENGTH(@xml) AS [XmlBytes],
       DATALENGTH(CONVERT(VARCHAR(MAX), @xml)) AS [VarcharBytes];

-- More "typical" XML (repeated element names -- all "element1"):
DECLARE @xml2 XML = '<root><element1>test</element1><element1>test</element1>
<element1>test</element1><element1>test</element1><element1>test</element1></root>';
SELECT DATALENGTH(@xml2) AS [XmlBytes],
       DATALENGTH(CONVERT(VARCHAR(MAX), @xml2)) AS [VarcharBytes];

Résultats:

ElementNames    XmlBytes    VarcharBytes
------------    --------    ------------
Unique          197         138
Non-Unique      109         138
6
Solomon Rutzky

De la DOCS sur Type de données XML et colonnes (SQL Server)

Les données sont stockées dans une représentation interne préservant le contenu XML des données. Cette représentation interne comprend des informations sur la hiérarchie de confinement, la commande de document et les valeurs d'élément et d'attribut. Spécifiquement, la teneur en infosé des données XML est préservée. Pour plus d'informations sur INFOSET, visitez http://www.w3.org/tr/xml-infoset . La teneur en infosé peut ne pas être une copie identique du texte XML, car les informations suivantes ne sont pas conservées: espaces blancs insignifiants, ordre des attributs, préfixes d'espace de noms et déclaration XML.

binary_representation_size Est grossièrement data + information about the containment hierarchy, document order, and element and attribute values - insignificant white spaces, order of attributes, namespace prefixes, and XML declaration

Ce n'est pas une victoire claire si vous n'avez pas de préfixes d'espace de noms et que vous stockez simplement plus de données.

Il est également mentionné explicitement dans les docs que vous pouvez simplement utiliser nvarchar(max) Si vous ne stockez et ne vous souciez pas des fonctionnalités ou de la validation,

Si aucune de ces conditions [la nécessité de fonctionnalités avancées] n'est remplie, vous devez utiliser le modèle de données relationnelle. Par exemple, si vos données sont au format XML, votre application utilise simplement la base de données pour stocker et récupérer les données, une colonne [n]varchar(max) est tout ce dont vous avez besoin. Stocker les données dans une colonne XML présente des avantages supplémentaires. Cela inclut la présentation du moteur à déterminer que les données sont bien formées ou valides, et comprennent également la prise en charge de la requête à grain fin et des mises à jour dans les données XML.

2
Evan Carroll

SQL Server 2016 introduit le COMPRESSE Fonction. Appliquer cela à l'exemple de @ Solomon:

... DATALENGTH(COMPRESS(CONVERT(VARCHAR(MAX), @xml))) AS [VarcharCompressed];

... DATALENGTH(COMPRESS(CONVERT(VARCHAR(MAX), @xml2))) AS [VarcharCompressed];

Les économies d'autres espaces sont obtenues:

ElementNames    XmlBytes    VarcharBytes  VarcharCompressed
------------    --------    ------------  -----------------
Unique          197         138           72
Non-Unique      109         138           49

Il convient de noter que l'espace est enregistré pour des noms d'éléments uniques et répétés.

0
Michael Green