sql >> Base de Datos >  >> RDS >> Sqlserver

SELECCIONAR PARA XML AUTO y devolver tipos de datos

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.