Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

XML Server Ottimizzazione delle prestazioni XML

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...