Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

SELECT FOR XML AUTO et renvoie les types de données

FOR XML a été introduit dans SQL Server 2000.

SQL Server 2000 n'avait pas MAX les types de données ou le XML Type de données. Il n'était pas non plus possible d'utiliser FOR XML dans une sous-requête.

L'article Que renvoie FOR XML côté serveur ? explique

Dans SQL Server 2000 ... FOR XML ... a été implémenté dans la couche de code entre le processeur de requêtes et la couche de transport de données ... le processeur de requêtes produit le résultat de la même manière que sans FOR XML puis FOR XML code formate l'ensemble de lignes en XML. Pour des performances de publication XML maximales FOR XML effectue le formatage XML à la vapeur de l'ensemble de lignes résultant et envoie directement sa sortie au code TDS côté serveur en petits morceaux sans mettre en mémoire tampon le XML entier dans l'espace du serveur. La taille du morceau est de 2033 caractères UCS-2. Ainsi, un XML supérieur à 2033 caractères UCS-2 est envoyé au côté client dans plusieurs lignes contenant chacune un morceau de XML. SQL Server utilise un nom de colonne prédéfini pour cet ensemble de lignes avec une colonne de type NTEXT -"XML_F52E2B61-18A1-11d1-B105-00805F49916B ” – pour indiquer un ensemble de lignes XML fragmenté dans le codage UTF-16.

Il semble donc que cela soit toujours implémenté de la même manière pour le niveau supérieur FOR XML dans les versions ultérieures également.

SQL Server 2005 a introduit la possibilité d'utiliser FOR XML dans les sous-requêtes (ce qui signifie que celles-ci doivent maintenant être gérées par le processeur de requêtes plutôt que par une couche extérieure lors de la transmission des résultats au client)

Le même article explique que ceux-ci seront tapés comme NVARCHAR(MAX) ou XML dépend de la présence ou non d'un type directives.

En plus de la différence de type de données, cela signifie le SELECT supplémentaire wrapper peut faire une différence drastique dans les performances si #tab est grand.

/*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

Il est possible de voir les différentes approches dans les piles d'appels ainsi que les plans d'exécution.

Diffusion directe

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    

Avec sous-requête

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

Les deux finissent par appeler le même code XML sous-jacent mais la version "déballée" n'a pas d'itérateurs XML dans le plan lui-même, le résultat est obtenu en remplaçant les appels de méthode de CXStmtSelect avec CXStmtXMLSelect à la place (représenté dans le plan sous la forme d'un nœud racine de sélection XML plutôt que d'un ancien simple Select).

Sur SQL Server 2016 CTP3, je vois toujours ntext pour le niveau supérieur FOR XML . Cependant niveau supérieur FOR JSON apparaît comme nvarchar(max)

Au moins dans le CTP, le nom de la colonne spéciale JSON contient toujours le GUID F52E2B61-18A1-11d1-B105-00805F49916B malgré le fait que l'origine de ceci soit l'interface IXMLDocument.

Les plans se ressemblent beaucoup bien que le XML Select soit remplacé par un JSON Select

BTW :Sur la version Microsoft SQL Server 2014 - 12.0.4213.0 (X64) Je ne vois aucune différence de comportement entre les tables temporaires et les tables permanentes. Cela est probablement dû aux différents @@Version entre les environnements que votre question utilise http://sqlfiddle.com/ (12.0.2000.8) et https://data.stackexchange.com/ (12.0.4213.0).

Peut-être qu'un bogue a été corrigé dans sys.dm_exec_describe_first_result_set entre les deux versions de 2014.

En 2012 j'obtiens les mêmes résultats que Shnugo sur 11.0.5343.0 (avec NULL dans les trois premières lignes) mais après avoir installé SP3 11.0.6020.0, j'obtiens le même résultat que vos premiers résultats indiqués dans la question.