FOR XML
werd geïntroduceerd in SQL Server 2000.
SQL Server 2000 had geen MAX
datatypes of de XML
data type. Het was ook niet mogelijk om FOR XML
. te gebruiken in een subquery.
Het artikel Wat levert server-side FOR XML op? legt uit
In SQL Server 2000 ...
FOR XML
... werd geïmplementeerd in de codelaag tussen de queryprocessor en de datatransportlaag ... de queryprocessor produceert het resultaat op dezelfde manier als zonderFOR XML
en danFOR XML
code maakt de rijenset op als XML. Voor maximale XML-publicatieprestatiesFOR XML
voert steaming XML-opmaak uit van de resulterende rijenset en stuurt de uitvoer rechtstreeks naar de server-side TDScode in kleine stukjes zonder hele XML in de serverruimte te bufferen. De chunk-grootte is 2033 UCS-2-tekens. XML die groter is dan 2033UCS-2-tekens wordt dus naar de client verzonden in meerdere rijen die elk een deel van de XML bevatten. SQL Server gebruikt een vooraf gedefinieerde kolomnaam voor deze rijenset met één kolom van het typeNTEXT
-“XML_F52E2B61-18A1-11d1-B105-00805F49916B
” – om chunked XMLrowset in UTF-16-codering aan te geven.
Het lijkt er dus op dat dit nog steeds op dezelfde manier wordt geïmplementeerd voor FOR XML
op het hoogste niveau ook in latere versies.
SQL Server 2005 introduceerde de mogelijkheid om FOR XML
te gebruiken in subquery's (wat betekent dat deze nu moeten worden afgehandeld door de queryprocessor in plaats van een laag erbuiten terwijl de resultaten naar de client worden gestreamd)
In hetzelfde artikel wordt uitgelegd dat deze worden getypt als NVARCHAR(MAX)
of XML
afhankelijk van de aanwezigheid of niet van een type
richtlijn.
Naast het verschil in datatype betekent dit ook de extra SELECT
wrapper kan een drastisch verschil in prestatie maken als #tab
is groot.
/*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
Het is mogelijk om de verschillende benaderingen in de call-stacks en uitvoeringsplannen te zien.
Direct gestreamd
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
Met subquery
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
Beide roepen uiteindelijk dezelfde onderliggende XML-code aan, maar de "uitgepakte" versie heeft geen XML-iterators in het plan zelf, het resultaat wordt bereikt door methodeaanroepen van CXStmtSelect
te vervangen met CXStmtXMLSelect
in plaats daarvan (weergegeven in het plan als een XML Select-hoofdknooppunt in plaats van een gewone oude Select).
Op SQL Server 2016 CTP3 zie ik nog steeds ntext
voor topniveau FOR XML
. Maar op het hoogste niveau FOR JSON
verschijnt als nvarchar(max)
In de CTP bevat de speciale JSON-kolomnaam tenminste nog de GUID F52E2B61-18A1-11d1-B105-00805F49916B
ondanks het feit dat de oorsprong hiervan de IXMLDocument Interface is.
De plannen zien er ongeveer hetzelfde uit, hoewel de XML Select is vervangen door een JSON Select
BTW:Op build Microsoft SQL Server 2014 - 12.0.4213.0 (X64)
Ik zie geen verschil in gedrag tussen tijdelijke tabellen en permanente tabellen. Dit komt waarschijnlijk door de verschillende @@Version
tussen de omgevingen die uw vraag gebruikt http://sqlfiddle.com/ (12.0.2000.8) en https://data.stackexchange.com/ (12.0.4213.0).
Misschien is er een fout opgelost in sys.dm_exec_describe_first_result_set
tussen de twee 2014 builds.
In 2012 krijg ik dezelfde resultaten als Shnugo op 11.0.5343.0 (met NULL
in de eerste drie rijen) maar na het installeren van SP3 11.0.6020.0 krijg ik hetzelfde als uw eerste resultaten die in de vraag worden getoond.