FOR XML
se introdujo en SQL Server 2000.
SQL Server 2000 no tenía MAX
tipos de datos o el XML
tipo de datos. Tampoco era posible usar FOR XML
en una subconsulta.
El artículo ¿Qué devuelve FOR XML del lado del servidor? explica
En SQL Server 2000... FOR XML
... se implementó en la capa de código entre el procesador de consultas y la capa de transporte de datos ... el procesador de consultas produce el resultado de la misma manera que sin FOR XML
y luego FOR XML
el código formatea el conjunto de filas como XML. Para obtener el máximo rendimiento de publicación XML FOR XML
formatea XML al vapor del conjunto de filas resultante y envía directamente su salida al código TDS del lado del servidor en pequeños fragmentos sin almacenar en búfer todo el XML en el espacio del servidor. El tamaño del fragmento es de 2033 caracteres UCS-2. Por lo tanto, el XML de más de 2033 caracteres UCS-2 se envía al lado del cliente en varias filas, cada una de las cuales contiene una parte del XML. SQL Server usa un nombre de columna predefinido para este conjunto de filas con una columna de tipo NTEXT
-“XML_F52E2B61-18A1-11d1-B105-00805F49916B
”:para indicar XMLrowset fragmentado en codificación UTF-16.
Entonces parece que esto todavía se implementa de la misma manera para el nivel superior FOR XML
en versiones posteriores también.
SQL Server 2005 introdujo la capacidad de usar FOR XML
en subconsultas (lo que significa que ahora deben ser manejadas por el procesador de consultas en lugar de una capa externa mientras transmite los resultados al cliente)
El mismo artículo explica que estos se escribirán como NVARCHAR(MAX)
o XML
dependiendo de la presencia o no de un type
directiva.
Además de la diferencia de tipo de datos, esto significa el SELECT
adicional wrapper puede marcar una diferencia drástica en el rendimiento si #tab
es grande.
/*Can be streamed straight out to client without using server storage*/
SELECT col
FROM #tab
FOR XML AUTO
/*XML constructed in its entirety in tempdb first*/
SELECT(SELECT col
FROM #tab
FOR XML AUTO) AS wrapped_subquery
Es posible ver los diferentes enfoques en las pilas de llamadas, así como los planes de ejecución.
Transmisión directa
sqllang.dll!CXMLExecContext::AddTagAndAttributes() + 0x5a9 bytes
sqllang.dll!CXMLExecContext::AddXMLRow() + 0x2b7 bytes
sqltses.dll!CEsExec::FastMoveEval() + 0x9c bytes
sqllang.dll!CXStmtQuery::ErsqExecuteQuery() + 0x280 bytes
sqllang.dll!CXStmtXMLSelect::WrapExecute() + 0x2d7 bytes
sqllang.dll!CXStmtXMLSelect::XretDoExecute() + 0x355 bytes
sqllang.dll!CXStmtXMLSelect::XretExecute() + 0x46 bytes
sqllang.dll!CMsqlExecContext::ExecuteStmts<1,1>() + 0x368 bytes
sqllang.dll!CMsqlExecContext::FExecute() + 0x6cb bytes
sqllang.dll!CSQLSource::Execute() + 0x3ee bytes
sqllang.dll!process_request() + 0x757 bytes
Con consulta secundaria
sqllang.dll!CXMLExecContext::AddTagAndAttributes() + 0x5a9 bytes
sqllang.dll!CXMLExecContext::AddXMLRow() + 0x2b7 bytes
sqllang.dll!CForXmlSerialize::ProcessRow() + 0x19 bytes
sqllang.dll!CUDXR_Base::PushRow() + 0x30 bytes
sqlmin.dll!CQScanUdx::Open() + 0xd5 bytes
sqlmin.dll!CQueryScan::StartupQuery() + 0x170 bytes
sqllang.dll!CXStmtQuery::SetupQueryScanAndExpression() + 0x391 bytes
sqllang.dll!CXStmtQuery::InitForExecute() + 0x34 bytes
sqllang.dll!CXStmtQuery::ErsqExecuteQuery() + 0x217 bytes
sqllang.dll!CXStmtSelect::XretExecute() + 0xed bytes
sqllang.dll!CMsqlExecContext::ExecuteStmts<1,1>() + 0x368 bytes
sqllang.dll!CMsqlExecContext::FExecute() + 0x6cb bytes
sqllang.dll!CSQLSource::Execute() + 0x3ee bytes
sqllang.dll!process_request() + 0x757 bytes
Ambos terminan llamando al mismo código XML subyacente, pero la versión "desenvuelta" no tiene ningún iterador XML en el plan en sí, el resultado se logra al reemplazar las llamadas a métodos de CXStmtSelect
con CXStmtXMLSelect
en su lugar (representado en el plan como un nodo raíz XML Select en lugar de un simple Select antiguo).
En SQL Server 2016 CTP3 todavía veo ntext
para nivel superior FOR XML
. Sin embargo, nivel superior FOR JSON
aparece como nvarchar(max)
Al menos en el CTP, el nombre de la columna especial JSON aún contiene el GUID F52E2B61-18A1-11d1-B105-00805F49916B
a pesar de que el origen de este es la Interfaz IXMLDocument.
Los planes se parecen mucho, aunque XML Select se reemplaza con JSON Select
Por cierto:en la compilación Microsoft SQL Server 2014 - 12.0.4213.0 (X64)
No veo ninguna diferencia en el comportamiento entre tablas temporales y tablas permanentes. Esto probablemente se deba a las diferentes @@Version
entre los entornos que utiliza su pregunta http://sqlfiddle.com/ (12.0.2000.8) y https://data.stackexchange.com/ (12.0.4213.0).
Tal vez se corrigió un error en sys.dm_exec_describe_first_result_set
entre las dos versiones de 2014.
En 2012 obtengo los mismos resultados que Shnugo en 11.0.5343.0 (con NULL
en las primeras tres filas) pero después de instalar SP3 11.0.6020.0 obtengo los mismos resultados iniciales que se muestran en la pregunta.