FOR XML
wurde in SQL Server 2000 eingeführt.
SQL Server 2000 hatte MAX
nicht Datentypen oder das XML
Datentyp. Es war auch nicht möglich, FOR XML
zu verwenden in einer Unterabfrage.
Der Artikel Was gibt serverseitig FOR XML zurück? erklärt
In SQL Server 2000 ... FOR XML
... wurde in der Codeschicht zwischen Abfrageprozessor und Datentransportschicht implementiert ... der Abfrageprozessor erzeugt das Ergebnis genauso wie ohne FOR XML
und dann FOR XML
code formatiert das Rowset als XML. Für maximale XML-Veröffentlichungsleistung FOR XML
führt eine Steaming-XML-Formatierung des resultierenden Rowsets durch und sendet seine Ausgabe direkt in kleinen Blöcken an den serverseitigen TDScode, ohne den gesamten XML-Code im Serverbereich zu puffern. Die Blockgröße beträgt 2033 UCS-2-Zeichen. Daher wird XML mit mehr als 2033 UCS-2-Zeichen in mehreren Zeilen, die jeweils einen Teil des XML enthalten, an die Clientseite gesendet. SQL Server verwendet einen vordefinierten Spaltennamen für dieses Rowset mit einer Spalte vom Typ NTEXT
-“XML_F52E2B61-18A1-11d1-B105-00805F49916B
” – um ein chunked XMLrowset in UTF-16-Codierung anzuzeigen.
Es scheint also, dass dies immer noch auf die gleiche Weise für FOR XML
der obersten Ebene implementiert wird auch in späteren Versionen.
SQL Server 2005 hat die Möglichkeit eingeführt, FOR XML
zu verwenden in Unterabfragen (was bedeutet, dass diese jetzt vom Abfrageprozessor gehandhabt werden müssen und nicht von einer Schicht außerhalb davon, während die Ergebnisse zum Client gestreamt werden)
Derselbe Artikel erklärt, dass diese als NVARCHAR(MAX)
eingegeben werden oder XML
abhängig vom Vorhandensein oder Nichtvorhandensein eines type
Richtlinie.
Neben dem Datentypunterschied bedeutet dies den Zusatz SELECT
Wrapper kann einen drastischen Leistungsunterschied bewirken, wenn #tab
ist groß.
/*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 ist möglich, die verschiedenen Ansätze in den Call-Stacks sowie Ausführungsplänen zu sehen.
Direkt gestreamt
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
Mit Unterabfrage
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 rufen am Ende denselben zugrunde liegenden XML-Code auf, aber die „ausgepackte“ Version hat keine XML-Iteratoren im Plan selbst, das Ergebnis wird durch Ersetzen von Methodenaufrufen von CXStmtSelect
erreicht mit CXStmtXMLSelect
stattdessen (im Plan als XML-Select-Root-Knoten dargestellt und nicht als einfaches altes Select).
Auf SQL Server 2016 CTP3 sehe ich immer noch ntext
für oberste Ebene FOR XML
. Jedoch oberste Ebene FOR JSON
wird als nvarchar(max)
angezeigt
Zumindest im CTP enthält der JSON-Sonderspaltenname noch die GUID F52E2B61-18A1-11d1-B105-00805F49916B
obwohl der Ursprung davon das IXMLDocument Interface ist.
Die Pläne sehen ziemlich gleich aus, obwohl die XML-Auswahl durch eine JSON-Auswahl ersetzt wurde
Übrigens:Auf Build Microsoft SQL Server 2014 - 12.0.4213.0 (X64)
Ich sehe keinen Unterschied im Verhalten zwischen temporären Tabellen und permanenten Tabellen. Das liegt wahrscheinlich an der unterschiedlichen @@Version
zwischen den Umgebungen, die Ihre Frage verwendet, http://sqlfiddle.com/ (12.0.2000.8) und https://data.stackexchange.com/ (12.0.4213.0).
Möglicherweise wurde ein Fehler in sys.dm_exec_describe_first_result_set
behoben zwischen den beiden Builds von 2014.
Auf 2012 erhalte ich die gleichen Ergebnisse wie Shnugo auf 11.0.5343.0 (mit NULL
in den ersten drei Zeilen), aber nach der Installation von SP3 11.0.6020.0 erhalte ich dieselben Ergebnisse wie Ihre ersten Ergebnisse, die in der Frage gezeigt werden.