Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

SELECT FOR XML AUTO und Datentypen zurückgeben

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.