FOR XML
беше въведен в SQL Server 2000.
SQL Server 2000 нямаше MAX
типове данни или XML
тип данни. Нито беше възможно да се използва FOR XML
в подзаявка.
Статията Какво връща сървърната страна FOR XML? обяснява
В SQL Server 2000 ...
FOR XML
... беше имплементиран в слоя код между процесора за заявки и транспортния слой на данни ... процесорът на заявки произвежда резултата по същия начин, както безFOR XML
и след товаFOR XML
кодът форматира набора от редове като XML. За максимална производителност на XML публикуванеFOR XML
прави разпределящо XML форматиране на резултантния набор от редове и директно изпраща неговия изход към TDScode от страна на сървъра на малки парчета, без да буферира целия XML в сървърното пространство. Размерът на парчето е 2033 UCS-2 знака. По този начин XML, по-голям от 2033UCS-2 знака, се изпраща на страната на клиента в множество реда, всеки от които съдържа част от XML. SQL Server използва предварително дефинирано име на колона за този набор от редове с една колона от типNTEXT
-“XML_F52E2B61-18A1-11d1-B105-00805F49916B
” – за указване на XMLrowset на парчета в UTF-16 кодиране.
Така че изглежда, че това все още се изпълнява по същия начин за най-високо ниво FOR XML
и в по-късни версии.
SQL Server 2005 въведе възможността за използване на FOR XML
в подзаявки (което означава, че те сега трябва да се обработват от процесора на заявки, а не от слой извън него, докато се предават резултатите към клиента)
Същата статия обяснява, че те ще бъдат въведени като NVARCHAR(MAX)
или XML
в зависимост от наличието или не на type
директива.
Освен разликата в типа данни, това означава допълнителния SELECT
wrapper може да направи драстична разлика в производителността, ако #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
вместо това (представен в плана като главен възел на XML Select, а не като обикновен стар Select).
На SQL Server 2016 CTP3 все още виждам ntext
за най-високо ниво FOR XML
. Въпреки това най-високо ниво FOR JSON
се показва като nvarchar(max)
Поне в CTP името на специалната колона в JSON все още съдържа GUID F52E2B61-18A1-11d1-B105-00805F49916B
въпреки факта, че произходът на това е IXMLDocument Interface.
Плановете изглеждат почти еднакви, въпреки че XML Select е заменен с JSON Select
BTW:При компилация 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
между двете версии от 2014 г.
През 2012 г. получавам същите резултати като Shnugo на 11.0.5343.0 (с NULL
в първите три реда), но след инсталирането на SP3 11.0.6020.0 получавам същото като първоначалните ви резултати, показани във въпроса.