FOR XML
został wprowadzony w SQL Server 2000.
SQL Server 2000 nie miał MAX
typy danych lub XML
typ danych. Nie było też możliwości użycia FOR XML
w podzapytaniu.
Artykuł Co zwraca strona serwera FOR XML? wyjaśnia
W SQL Server 2000... FOR XML
... został zaimplementowany w warstwie kodu między procesorem zapytań a warstwą transportu danych ... procesor zapytań generuje wynik w taki sam sposób, jak bez FOR XML
a następnie FOR XML
kod formatuje zestaw wierszy jako XML. Dla maksymalnej wydajności publikowania XML FOR XML
robi parowe formatowanie XML powstałego zestawu wierszy i bezpośrednio wysyła swoje dane wyjściowe do TDScode po stronie serwera w małych porcjach bez buforowania całego XML w przestrzeni serwera. Rozmiar porcji to 2033 znaków UCS-2. W ten sposób XML większy niż 2033UCS-2 znaków jest wysyłany po stronie klienta w wielu wierszach, z których każdy zawiera fragment kodu XML. SQL Server używa wstępnie zdefiniowanej nazwy kolumny dla tego zestawu wierszy z jedną kolumną typu NTEXT
-„XML_F52E2B61-18A1-11d1-B105-00805F49916B
” – aby wskazać fragmentaryczny zestaw XMLrowset w kodowaniu UTF-16.
Wygląda więc na to, że jest to nadal zaimplementowane w ten sam sposób dla najwyższego poziomu FOR XML
w późniejszych wersjach.
SQL Server 2005 wprowadził możliwość używania FOR XML
w podzapytaniach (co oznacza, że muszą one być teraz obsługiwane przez procesor zapytań, a nie przez warstwę poza nim podczas przesyłania wyników do klienta)
W tym samym artykule wyjaśniono, że zostaną one wpisane jako NVARCHAR(MAX)
lub XML
zależnie od obecności lub nie type
dyrektywa.
Oprócz różnicy typów danych oznacza to dodatkowy SELECT
wrapper może spowodować drastyczną różnicę w wydajności, jeśli #tab
jest duży.
/*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
Można zobaczyć różne podejścia w stosach wywołań, a także w planach wykonania.
Przesyłane bezpośrednio
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
Z zapytaniem podrzędnym
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
Oba kończą wywołanie tego samego bazowego kodu XML, ale wersja „nieopakowana” nie ma żadnych iteratorów XML w samym planie, wynik jest osiągany przez zastąpienie wywołań metod z CXStmtSelect
z CXStmtXMLSelect
zamiast tego (reprezentowany w planie jako węzeł główny XML Select zamiast zwykłego starego Select).
Na SQL Server 2016 CTP3 nadal widzę ntext
dla najwyższego poziomu FOR XML
. Jednak najwyższego poziomu FOR JSON
pojawia się jako nvarchar(max)
Przynajmniej w CTP specjalna nazwa kolumny JSON nadal zawiera identyfikator GUID F52E2B61-18A1-11d1-B105-00805F49916B
pomimo faktu, że źródłem tego jest interfejs IXMLDocument.
Plany wyglądają bardzo podobnie, chociaż XML Select został zastąpiony przez JSON Select
BTW:W kompilacji Microsoft SQL Server 2014 - 12.0.4213.0 (X64)
Nie widzę żadnej różnicy w zachowaniu między tabelami tymczasowymi a tabelami stałymi. Jest to prawdopodobnie spowodowane różnymi @@Version
między środowiskami, w których Twoje pytanie używa http://sqlfiddle.com/ (12.0.2000.8) i https://data.stackexchange.com/ (12.0.4213.0).
Może błąd został naprawiony w sys.dm_exec_describe_first_result_set
między dwoma wersjami z 2014 roku.
W 2012 otrzymuję takie same wyniki jak Shnugo na 11.0.5343.0 (z NULL
w pierwszych trzech wierszach), ale po zainstalowaniu dodatku SP3 11.0.6020.0 otrzymuję to samo, co początkowe wyniki pokazane w pytaniu.