sql >> Database >  >> RDS >> Sqlserver

KIES VOOR XML AUTO en retourneer datatypes

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 dan FOR XML code maakt de rijenset op als XML. Voor maximale XML-publicatieprestaties FOR 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 type NTEXT -“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.



  1. Sqlite voegt geen gegevens in de 2e tabel in

  2. MySQL-substringextractie met scheidingsteken

  3. Hoe aangepaste kenmerken toevoegen aan SQL-verbindingsreeks?

  4. MySQL haalt variabele op uit opgeslagen procedure in PHP PDO