Ich kann Ihnen eine Antwort und eine Vermutung geben:
Zuerst verwende ich eine deklarierte Tabellenvariable zum Mocken Ihr Szenario:
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>');
--Diese Abfrage liest das XML mit einem Cast aus einem sub-select . Sie können einen CTE
verwenden stattdessen, aber das sollte nur syntaktischer Zucker sein...
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);
--Der zweite Teil verwendet eine Tabelle, um in das typisierte XML zu schreiben und von dort zu lesen:
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);
Warum ist /text()
schneller als ohne /text()
?
Wenn Sie sich mein Beispiel ansehen, ist der Inhalt eines Elements alles vom öffnenden Tag bis zum schließenden Tag . Der text()
eines Elements ist der schwebende Text zwischen diesen Tags. Sie können dies in den Ergebnissen der Auswahl oben sehen. Der text()
ist ein separat gespeicherter Teil in einer Baumstruktur tatsächlich (lesen Sie den nächsten Abschnitt). Das Abrufen ist eine Ein-Schritt-Aktion . Andernfalls muss eine komplexe Struktur analysiert werden, um alles zwischen dem öffnenden Tag und seinem entsprechenden schließenden Tag zu finden - selbst wenn es nichts anderes als den text()
gibt .
Warum sollte ich XML im richtigen Typ speichern?
XML ist nicht nur Text mit ein paar dummen Extrazeichen! Es ist ein Dokument mit einer komplexen Struktur. Das XML wird nicht als Text gespeichert, den Sie sehen . XML wird in einer Baumstruktur gespeichert. Immer wenn Sie einen String, der ein XML darstellt, in ein echtes XML umwandeln, muss diese sehr teure Arbeit erledigt werden. Wenn Ihnen das XML (oder eine andere Ausgabe) präsentiert wird, wird die darstellende Zeichenfolge von Grund auf (neu) erstellt.
Warum ist der vorgefertigte Ansatz schneller
Das ist eine Vermutung...
In meinem Beispiel sind beide Ansätze ziemlich gleich und führen zu (fast) demselben Ausführungsplan.
SQL Server wird nicht alles so abarbeiten, wie Sie es vielleicht erwarten. Dies ist kein prozedurales System, in dem Sie sagen:Mach dies, dann mach dies und danach mach das! . Sie sagen der Engine, was Sie wollen, und die Engine entscheidet, wie sie dies am besten macht. Und die Engine ist damit ziemlich gut!
Bevor die Ausführung beginnt, versucht die Engine, die Kosten der Anflüge zu schätzen. CONVERT
(oder CAST
) ist eine ziemlich billige Operation. Es könnte sein, dass die Engine entscheidet, die Liste Ihrer Aufrufe abzuarbeiten und den Cast für jeden einzelnen Bedarf immer wieder neu zu machen, weil sie denkt, dass dies billiger ist als die teure Erstellung einer abgeleiteten Tabelle...