Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

SELEZIONA PER XML AUTO e restituisci i tipi di dati

FOR XML è stato introdotto in SQL Server 2000.

SQL Server 2000 non disponeva di MAX tipi di dati o XML tipo di dati. Né era possibile utilizzare FOR XML in una sottoquery.

L'articolo Cosa restituisce il lato server FOR XML? spiega

In SQL Server 2000 ... FOR XML ... è stato implementato nel livello di codice tra il Query Processor e il livello di trasporto dei dati ... il Query Processor produce il risultato allo stesso modo di senzaFOR XML e poi FOR XML code formatta il set di righe come XML. Per le massime prestazioni di pubblicazione XML FOR XML esegue la formattazione XML a vapore del set di righe risultante e invia direttamente il suo output al codice TDS lato server in piccoli blocchi senza memorizzare nel buffer l'intero XML nello spazio del server. La dimensione del blocco è di 2033 caratteri UCS-2. Pertanto, l'XML di dimensioni superiori a 2033 UCS-2 caratteri viene inviato al lato client in più righe, ciascuna contenente un blocco dell'XML. SQL Server utilizza un nome di colonna predefinito per questo set di righe con una colonna di tipo NTEXT -“XML_F52E2B61-18A1-11d1-B105-00805F49916B ” – per indicare un set di righe XML in blocchi nella codifica UTF-16.

Quindi sembra che questo sia ancora implementato allo stesso modo per FOR XML di livello superiore anche nelle versioni successive.

SQL Server 2005 ha introdotto la possibilità di utilizzare FOR XML nelle sottoquery (il che significa che queste ora devono essere gestite dal Query Processor piuttosto che da un livello esterno durante lo streaming dei risultati al client)

Lo stesso articolo spiega che questi verranno digitati come NVARCHAR(MAX) o XML dipendente dalla presenza o meno di un type direttiva.

Oltre alla differenza del tipo di dati, ciò significa l'aggiunta di SELECT wrapper può fare una drastica differenza in termini di prestazioni se #tab è 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

È possibile vedere i diversi approcci negli stack di chiamate e nei piani di esecuzione.

Streaming diretto

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 sottointerrogazione

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

Entrambi finiscono per chiamare lo stesso codice XML sottostante ma la versione "non imballata" non ha iteratori XML nel piano stesso, il risultato si ottiene sostituendo le chiamate al metodo da CXStmtSelect con CXStmtXMLSelect invece (rappresentato nel piano come un nodo radice XML Select anziché un semplice vecchio Select).

Su SQL Server 2016 CTP3 vedo ancora ntext per il livello superiore FOR XML . Tuttavia FOR JSON di livello superiore si presenta come nvarchar(max)

Almeno nel CTP il nome della colonna speciale JSON contiene ancora il GUID F52E2B61-18A1-11d1-B105-00805F49916B nonostante il fatto che l'origine di questo sia l'interfaccia IXMLDocument.

I piani sembrano più o meno gli stessi anche se XML Select viene sostituito con un JSON Select

A proposito:su build Microsoft SQL Server 2014 - 12.0.4213.0 (X64) Non vedo alcuna differenza nel comportamento tra tabelle temporanee e tabelle permanenti. Questo è probabilmente dovuto alla diversa @@Version tra gli ambienti la tua domanda utilizza http://sqlfiddle.com/ (12.0.2000.8) e https://data.stackexchange.com/ (12.0.4213.0).

Forse è stato corretto un bug in sys.dm_exec_describe_first_result_set tra le due build del 2014.

Nel 2012 ottengo gli stessi risultati di Shnugo su 11.0.5343.0 (con NULL nelle prime tre righe) ma dopo aver installato SP3 11.0.6020.0 ottengo gli stessi risultati iniziali mostrati nella domanda.