Je peux vous donner une réponse et une supposition :
J'utilise d'abord une variable de table déclarée pour maquette votre scénario :
DECLARE @tbl TABLE(s NVARCHAR(MAX));
INSERT INTO @tbl VALUES
(N'<root>
<SomeElement>This is first text of element1
<InnerElement>This is text of inner element1</InnerElement>
This is second text of element1
</SomeElement>
<SomeElement>This is first text of element2
<InnerElement>This is text of inner element2</InnerElement>
This is second text of element2
</SomeElement>
</root>')
,(N'<root>
<SomeElement>This is first text of elementA
<InnerElement>This is text of inner elementA</InnerElement>
This is second text of elementA
</SomeElement>
<SomeElement>This is first text of elementB
<InnerElement>This is text of inner elementB</InnerElement>
This is second text of elementB
</SomeElement>
</root>');
--Cette requête lira le XML avec un cast d'une sous-sélection . Vous pouvez utiliser un CTE
à la place, mais cela ne devrait être que du sucre syntaxique...
SELECT se.value(N'(.)[1]','nvarchar(max)') SomeElementsContent
,se.value(N'(InnerElement)[1]','nvarchar(max)') InnerElementsContent
,se.value(N'(./text())[1]','nvarchar(max)') ElementsFirstText
,se.value(N'(./text())[2]','nvarchar(max)') ElementsSecondText
FROM (SELECT CAST(s AS XML) FROM @tbl) AS tbl(TheXml)
CROSS APPLY TheXml.nodes(N'/root/SomeElement') AS A(se);
--La deuxième partie utilise une table pour écrire dans le XML typé et lire à partir de là :
DECLARE @tbl2 TABLE(x XML)
INSERT INTO @tbl2
SELECT CAST(s AS XML) FROM @tbl;
SELECT se.value(N'(.)[1]','nvarchar(max)') SomeElementsContent
,se.value(N'(InnerElement)[1]','nvarchar(max)') InnerElementsContent
,se.value(N'(./text())[1]','nvarchar(max)') ElementsFirstText
,se.value(N'(./text())[2]','nvarchar(max)') ElementsSecondText
FROM @tbl2 t2
CROSS APPLY t2.x.nodes(N'/root/SomeElement') AS A(se);
Pourquoi /text()
plus rapide que sans /text()
?
Si vous regardez mon exemple, le contenu d'un élément est tout de la balise ouvrante à la balise fermante . Le text()
d'un élément est le texte flottant entre ces balises. Vous pouvez le voir dans les résultats de la sélection ci-dessus. Le text()
est une partie stockée séparément dans une structure arborescente en fait (lire la section suivante). Pour le récupérer, il s'agit d'une action en une seule étape . Sinon, une structure complexe doit être analysée pour trouver tout ce qui se trouve entre la balise d'ouverture et sa balise de fermeture correspondante - même s'il n'y a rien d'autre que le text()
.
Pourquoi devrais-je stocker XML dans le type approprié ?
XML n'est pas seulement du texte avec quelques caractères supplémentaires idiots ! C'est un document avec une structure complexe. Le XML n'est pas stocké comme le texte que vous voyez . XML est stocké dans une structure arborescente. Chaque fois que vous convertissez une chaîne, qui représente un XML, en un véritable XML, ce travail très coûteux doit être effectué. Lorsque le XML vous est présenté (ou à toute autre sortie), la chaîne de représentation est (re)construite à partir de zéro.
Pourquoi l'approche préfabriquée est-elle plus rapide
C'est une supposition...
Dans mon exemple, les deux approches sont assez égales et conduisent à (presque) le même plan d'exécution.
SQL Server ne fonctionnera pas tout comme vous pourriez vous y attendre. Ce n'est pas un système procédural où vous dites faites ceci, puis faites ceci et après faites ceci ! . Vous dites au moteur ce que vous voulez, et le moteur décide de la meilleure façon de le faire. Et le moteur est plutôt bon avec ça !
Avant le démarrage de l'exécution, le moteur essaie d'estimer les coûts des approches. CONVERT
(ou CAST
) est une opération plutôt bon marché. Il se peut que le moteur décide de travailler sur la liste de vos appels et de faire le casting pour chaque besoin unique encore et encore, car il pense que c'est moins cher que la création coûteuse d'une table dérivée...