FOR XML
SQLServer2000で導入されました。
SQLServer2000にはMAX
がありませんでした データ型またはXML
データ・タイプ。 FOR XML
を使用することもできませんでした サブクエリで。
記事サーバーサイドのFORXMLは何を返しますか?説明
SQLServer2000の場合...
FOR XML
...クエリプロセッサとデータトランスポート層の間のコード層に実装されました...クエリプロセッサは、FOR XML
がない場合と同じ方法で結果を生成します。 次に、FOR XML
コードは行セットをXMLとしてフォーマットします。 XMLパブリッシングのパフォーマンスを最大化するためにFOR XML
結果の行セットのXMLフォーマットをスチーミングし、その出力をサーバースペースにXML全体をバッファリングせずに小さなチャンクでサーバー側のTDScodeに直接送信します。チャンクサイズは2033UCS-2文字です。したがって、2033UCS-2文字より大きいXMLは、それぞれがXMLのチャンクを含む複数の行でクライアント側に送信されます。 SQL Serverは、この行セットに事前定義された列名をタイプNTEXT
の1つの列で使用します -「XML_F52E2B61-18A1-11d1-B105-00805F49916B
」–UTF-16エンコーディングでチャンク化されたXML行セットを示します。
したがって、これはトップレベルのFOR XML
でも同じ方法で実装されているようです。 それ以降のバージョンでも。
SQL Server 2005では、FOR XML
を使用する機能が導入されました。 サブクエリ内(つまり、結果をクライアントにストリーミングするときに、クエリプロセッサの外部のレイヤーではなく、クエリプロセッサで処理する必要があります)
同じ記事で、これらはNVARCHAR(MAX)
として入力されると説明されています またはXML
type
の有無によって異なります ディレクティブ。
データ型の違いだけでなく、これは追加のSELECT
を意味します #tab
の場合、ラッパーはパフォーマンスに大幅な違いをもたらす可能性があります 大きいです。
/*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
実行計画だけでなく、コールスタックのさまざまなアプローチを確認することができます。
直接ストリーミング
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
サブクエリあり
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
どちらも同じ基になるXMLコードを呼び出すことになりますが、「ラップされていない」バージョンにはプラン自体にXMLイテレーターが含まれていません。結果は、CXStmtSelect
からのメソッド呼び出しを置き換えることで実現されます。 CXStmtXMLSelect
を使用 代わりに(プランでは、単純な古いSelectではなくXML Selectルートノードとして表されます)。
SQL Server 2016 CTP3でも、ntext
が表示されます トップレベルのFOR XML
。ただし、トップレベルのFOR JSON
nvarchar(max)
として表示されます
少なくともCTPでは、JSON特殊列名にGUID F52E2B61-18A1-11d1-B105-00805F49916B
が含まれています。 これの起源はIXMLDocumentインターフェイスであるという事実にもかかわらず。
XMLSelectがJSONSelectに置き換えられていますが、計画はほとんど同じように見えます
ところで:ビルド時Microsoft SQL Server 2014 - 12.0.4213.0 (X64)
一時テーブルと永続テーブルの動作に違いは見られません。これはおそらく別の@@Version
によるものです 質問が使用する環境間では、http://sqlfiddle.com/(12.0.2000.8)とhttps://data.stackexchange.com/(12.0.4213.0)が使用されます。
sys.dm_exec_describe_first_result_set
でバグが修正された可能性があります 2つの2014ビルドの間。
2012年には、11.0.5343.0のShnugoと同じ結果が得られます(NULL
最初の3行)ですが、SP3 11.0.6020.0をインストールした後、質問に示されている最初の結果と同じ結果が得られます。