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 sansFOR XML
puisFOR XML
code formate l'ensemble de lignes en XML. Pour des performances de publication XML maximalesFOR 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 typeNTEXT
-"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.