Puedo darte una respuesta y una conjetura:
Primero uso una variable de tabla declarada para simular tu escenario:
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>');
--Esta consulta leerá el XML con una conversión de una subselección . Podrías usar un CTE
en cambio, pero esto debería ser solo azúcar sintáctico...
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 segunda parte usa una tabla para escribir en el XML escrito y leer desde allí:
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);
¿Por qué /text()
más rápido que sin /text()
?
Si miras mi ejemplo, el contenido de un elemento es todo desde la etiqueta de apertura hasta la etiqueta de cierre . El text()
de un elemento es el texto flotante entre estas etiquetas. Puede ver esto en los resultados de la selección anterior. El text()
es una parte almacenada por separado en una estructura de árbol en realidad (lea la siguiente sección). Para obtenerlo, es una acción de un solo paso . De lo contrario, se debe analizar una estructura compleja para encontrar todo entre la etiqueta de apertura y su correspondiente etiqueta de cierre, incluso si no hay nada más que el text()
.
¿Por qué debo almacenar XML en el tipo apropiado?
¡XML no es solo texto con algunos caracteres adicionales tontos! Es un documento con una estructura compleja. El XML no se almacena como el texto que ves . XML se almacena en una estructura de árbol. Cada vez que convierte una cadena, que representa un XML, en un XML real, se debe realizar este trabajo muy costoso. Cuando se le presenta el XML (o cualquier otro resultado), la cadena de representación se (re)construye desde cero.
¿Por qué el enfoque prefabricado es más rápido?
Esto es adivinar...
En mi ejemplo, ambos enfoques son bastante iguales y conducen a (casi) el mismo plan de ejecución.
SQL Server no funcionará todo de la forma en que podría esperarlo. Este no es un sistema procesal en el que dices ¡haz esto, luego haz esto y luego haz esto! . Le dices al motor lo que quieres y el motor decide cómo hacerlo mejor. ¡Y el motor es bastante bueno con esto!
Antes de que comience la ejecución, el motor intenta estimar los costos de los enfoques. CONVERT
(o CAST
) es una operación bastante barata. Podría ser que el motor decida trabajar en la lista de sus llamadas y hacer el reparto para cada necesidad individual una y otra vez, porque piensa que esto es más barato que la costosa creación de una tabla derivada...