Posso darti una risposta e un'ipotesi:
Per prima cosa utilizzo una variabile di tabella dichiarata per mock up il tuo scenario:
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>');
--Questa query leggerà l'XML escludendo una sottoselezione . Potresti usare un CTE
invece, ma questo dovrebbe essere solo zucchero sintattico...
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 seconda parte usa una tabella per scrivere nell'XML digitato e leggere da 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);
Perché è /text()
più veloce che senza /text()
?
Se guardi il mio esempio, il contenuto di un elemento è tutto dal tag di apertura fino al tag di chiusura . Il text()
di un elemento è il testo mobile tra questi tag. Puoi vederlo nei risultati della selezione sopra. Il text()
è una parte memorizzata separatamente in una struttura ad albero effettivamente (leggi la prossima sezione). Per recuperarlo, è un azione in un solo passaggio . Altrimenti è necessario analizzare una struttura complessa per trovare tutto ciò che si trova tra il tag di apertura e il tag di chiusura corrispondente, anche se non c'è nient'altro che il text()
.
Perché dovrei memorizzare XML nel tipo appropriato?
XML non è solo testo con alcuni stupidi caratteri extra! È un documento con una struttura complessa. L'XML non è memorizzato come testo visualizzato . XML è memorizzato in una struttura ad albero. Ogni volta che si esegue il cast di una stringa, che rappresenta un XML, in un XML reale, è necessario eseguire questo lavoro molto costoso. Quando l'XML ti viene presentato (o qualsiasi altro output) la stringa che rappresenta viene (ri)costruita da zero.
Perché l'approccio prefabbricato è più veloce
Questa è una supposizione...
Nel mio esempio entrambi gli approcci sono abbastanza uguali e portano (quasi) allo stesso piano di esecuzione.
SQL Server non funzionerà in tutto come ci si potrebbe aspettare. Questo non è un sistema procedurale in cui dichiari fai questo, poi fai questo e poi fai questo! . Dici al motore cosa vuoi e il motore decide come farlo al meglio. E il motore è abbastanza buono con questo!
Prima dell'inizio dell'esecuzione, il motore cerca di stimare i costi degli approcci. CONVERT
(o CAST
) è un'operazione piuttosto economica. Può darsi che il motore decida di stilare l'elenco delle tue chiamate e fare il cast per ogni singola esigenza più e più volte, perché pensa che questo sia più economico della costosa creazione di una tabella derivata...