Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

SELECT FOR XML AUTO e retornar tipos de dados


FOR XML foi introduzido no SQL Server 2000.

SQL Server 2000 não tinha MAX tipos de dados ou o XML tipo de dados. Nem foi possível usar FOR XML em uma subconsulta.

O artigo O que o lado do servidor FOR XML retorna? explica

No SQL Server 2000 ... FOR XML ... foi implementado na camada de código entre o processador de consultas e a camada de transporte de dados ... o processador de consultas produz o resultado da mesma forma que sem FOR XML e então FOR XML code formata o conjunto de linhas como XML. Para desempenho máximo de publicação XML FOR XML faz a formatação XML do conjunto de linhas resultante e envia diretamente sua saída para o código TDS do lado do servidor em pequenos pedaços sem buffer XML inteiro no espaço do servidor. O tamanho do bloco é de 2.033 caracteres UCS-2. Assim, XML com mais de 2033UCS-2 caracteres é enviado para o lado do cliente em várias linhas, cada uma contendo um pedaço do XML. O SQL Server usa um nome de coluna predefinido para este conjunto de linhas com uma coluna do tipo NTEXT -“XML_F52E2B61-18A1-11d1-B105-00805F49916B ” – para indicar o XMLrowset em partes na codificação UTF-16.

Portanto, parece que isso ainda é implementado da mesma maneira para FOR XML de nível superior em versões posteriores também.

O SQL Server 2005 introduziu a capacidade de usar FOR XML em subconsultas (o que significa que agora elas precisam ser tratadas pelo processador de consultas em vez de uma camada fora dele enquanto transmite os resultados para o cliente)

O mesmo artigo explica que eles serão digitados como NVARCHAR(MAX) ou XML dependente da presença ou não de um type diretiva.

Assim como a diferença de tipo de dados, isso significa o SELECT adicional wrapper pode fazer uma diferença drástica no desempenho 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

É possível ver as diferentes abordagens nas pilhas de chamadas, bem como os planos de execução.

Transmitido diretamente


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    

Com subconsulta


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

Ambos acabam chamando o mesmo código XML subjacente, mas a versão "desempacotada" não possui iteradores XML no próprio plano, o resultado é alcançado substituindo as chamadas de método de CXStmtSelect com CXStmtXMLSelect em vez disso (representado no plano como um nó raiz XML Select em vez de um Select simples e antigo).

No SQL Server 2016 CTP3, ainda vejo ntext para FOR XML de nível superior . No entanto, FOR JSON de nível superior aparece como nvarchar(max)



Pelo menos no CTP, o nome da coluna especial JSON ainda contém o GUID F52E2B61-18A1-11d1-B105-00805F49916B apesar do fato de que a origem disso é a Interface IXMLDocument.

Os planos parecem os mesmos, embora o XML Select seja substituído por um JSON Select



BTW:Na compilação Microsoft SQL Server 2014 - 12.0.4213.0 (X64) Não vejo nenhuma diferença de comportamento entre tabelas temporárias e tabelas permanentes. Isso provavelmente se deve a diferentes @@Version entre os ambientes que sua pergunta usa http://sqlfiddle.com/ (12.0.2000.8) e https://data.stackexchange.com/ (12.0.4213.0).

Talvez um bug tenha sido corrigido em sys.dm_exec_describe_first_result_set entre as duas versões de 2014.

Em 2012 recebo os mesmos resultados que Shnugo em 11.0.5343.0 (com NULL nas três primeiras linhas), mas depois de instalar o SP3 11.0.6020.0 recebo o mesmo que seus resultados iniciais mostrados na pergunta.