Выберите для XML AUTO и возвращайте типы данных



Во время игры с sys.dm_exec_describe_first_result_set я добираюсь до этой точки:



CREATE TABLE #tab(col INT, x XML );
INSERT INTO #tab(col,x) VALUES (1,NULL), (2,NULL), (3,'<a>x</a>');

SELECT 'Simple XML' AS description, name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT col
FROM #tab
FOR XML AUTO', NULL, 0)
UNION ALL
SELECT 'Wrapped with subquery', name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT(SELECT col
FROM #tab
FOR XML AUTO) AS wrapped_subquery', NULL, 0)
UNION ALL
SELECT 'XML column', name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT x FROM #tab ', NULL, 0)
UNION ALL
SELECT 'Casted XML', name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT CAST(''<o>O</o>'' AS XML) AS x', NULL, 0)
UNION ALL
SELECT 'Wrapped Casted XML', name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT (SELECT CAST(''<o>O</o>'' AS XML) AS x) AS wrapped', NULL, 0)
UNION ALL
SELECT 'Text value', name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT CAST(''aaa'' AS NTEXT) AS text_string', NULL, 0)
UNION ALL
SELECT 'Wrapped Text Value', name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT (SELECT CAST(''aaa'' AS NTEXT)) AS text_string_wrapped', NULL, 0)


LiveDemo



Вывод:



╔═══════════════════════╦═════════════════════════════════════════╦══════════════════╗
║ Description ║ name ║ system_type_name ║
╠═══════════════════════╬═════════════════════════════════════════╬══════════════════╣
║ Simple XML ║ XML_F52E2B61-18A1-11d1-B105-00805F49916 ║ ntext ║
║ Wrapped with subquery ║ wrapped_subquery ║ nvarchar(max) ║
║ XML column ║ x ║ xml ║
║ Casted XML ║ x ║ xml ║
║ Wrapped Casted XML ║ wrapped ║ xml ║
║ Text value ║ text_string ║ ntext ║
║ Wrapped Text Value ║ text_string_wrapped ║ ntext ║
╚═══════════════════════╩═════════════════════════════════════════╩══════════════════╝


И:



SELECT col        -- SSMS result grid - XML column
FROM #tab
FOR XML AUTO

SELECT(SELECT col -- text column
FROM #tab
FOR XML AUTO) AS wrapped_subquery


Вопросы:




  1. Почему FOR XML AUTO не возвращает XML/NVARCHAR(MAX) тип данных, но ntext (устаревший тип данных!)?

  2. как обертывание с подзапросом изменяет тип данных с ntext на nvarchar(max)?

  3. Почему те же правила не применяются к столбцам XML/NTEXT?


Я знаю, что мои вопросы могут быть техническими и внутренние операции, но я был бы благодарен за
какие-либо сведения или документация в MSDN / Connect?



Редактировать:



Забавная вещь, когда я использую обычную таблицу(не временную), она возвращает все ntext:



╔════════════════════════╦═══════════════════════════════════════╦══════════════════╗
║ description ║ name ║ system_type_name ║
╠════════════════════════╬═══════════════════════════════════════╬══════════════════╣
║ Simple XML ║ XML_F52E2B61-18A1-11d1-B105-00805F499 ║ ntext ║
║ Wrapped with subquery ║ wrapped_subquery ║ ntext ║
║ XML column ║ x ║ ntext ║
║ Casted XML ║ x ║ ntext ║
║ Wrapped Casted XML ║ wrapped ║ ntext ║
║ Text value ║ text_string ║ ntext ║
║ Wrapped Text Value ║ text_string_wrapped ║ ntext ║
╚════════════════════════╩═══════════════════════════════════════╩══════════════════╝


SqlFiddleDemo



Согласно TYPE directive:




Поддержка SQL Server для xml (Transact-SQL) позволяет дополнительно
запросите, чтобы результат запроса FOR XML был возвращен как тип данных xml указав директиву типа .



SQL Server возвращает клиенту данные экземпляра типа XML в виде
результат различных серверных конструкций, таких как для XML-запросов, которые используют
директива TYPE, или где тип данных xml используется для возврата XML
значения данных экземпляра из столбцов таблицы SQL и выходных параметров. В
код клиентского приложения, ADO.NET поставщик запрашивает эти XML-данные
введите информацию, которая будет отправлена с сервера в двоичной кодировке.
Однако, Если вы используете для XML без директивы TYPE, XML
данные возвращаются в виде строки типа
.




И:



SELECT 'Simple XML' AS description, name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT col AS col
FROM #tab
FOR XML AUTO, TYPE', NULL, 0)
UNION ALL
SELECT 'Wrapped with subquery', name, system_type_name
FROM sys.dm_exec_describe_first_result_set(
N'SELECT(SELECT col
FROM #tab
FOR XML AUTO,TYPE) AS wrapped_subquery', NULL, 0);


LiveDemo




  1. Почему ntext Не nvarchar(max) как в цитате the XML data comes back as a string type и где разница нормальная / временная таблица?

625   2  

2 ответов:

FOR XML был представлен в SQL Server 2000.

В SQL Server 2000 не было типов данных MAXили XML. Также невозможно было использовать FOR XML в подзапросе.

Статья что возвращает серверная часть для XML? объясняет

В SQL Server 2000 ... FOR XML... был реализовано в слое кода между процессором запросов и транспортный уровень данных ... обработчик запросов выдает результат так же, как и без него. FOR XML и затем код FOR XML форматирует набор строк как XML. Для максимального XML publishing performance FOR XML выполняет распаривание XML-форматирования результирующий набор строк и напрямую отправляет выходные данные на стороне сервера ТДС код в небольших кусках без буферизации всего XML в пространстве сервера. Размер блока составляет 2033 символа UCS-2. Таким образом, XML больше, чем 2033 Символы UCS-2 отправляются на клиентскую сторону в нескольких строках каждый содержащий часть XML-файла. SQL Server использует предопределенный столбец название для этого набор строк с одним столбцом типа NTEXT - "XML_F52E2B61-18A1-11d1-B105-00805F49916B – - для обозначения фрагментированного XML набор строк в кодировке UTF-16.

Таким образом, похоже, что это все еще реализуется таким же образом для верхнего уровня 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 вместо этого (представленный в плане как корневой узел XML Select, а не простой старый Select).


На SQL Server 2016 CTP3 я все еще вижу ntext для верхнего уровня FOR XML. Однако верхний уровень FOR JSON отображается как nvarchar(max)

Введите описание изображения здесь

По крайней мере, в CTP имя специального столбца JSON все еще содержит GUID F52E2B61-18A1-11d1-B105-00805F49916B, несмотря на то, что источником этого является интерфейс IXMLDocument.

Планы выглядят примерно так же, хотя XML Select заменен на JSON Select

Введите описание изображения здесь


Кстати: при сборке 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 году я получаю те же результаты, что и Шнуго на 11.0.5343.0 (с NULL в первых трех строках), но после установки SP3 11.0.6020.0 я получаю те же результаты, что и ваши первоначальные результаты, показанные в вопросе.

Интересный вопрос! NTEXT Действительно странно!

У меня есть идея о подзапросе: когда вы возвращаете XML, он всегда передается как строка, если вы не указываете TYPE (вы наверняка знаете это из вложенного XML с перекрестным применением или из конкатенации строки с материалом, где вы что-то видите это с TYPEи follwing .value() - и иногда "голый".

Я действительно не смог воспроизвести ваши результаты (SQL Server 2012 тоже). Простой copy'n'paste возвращается с (я хотел проверить с объявленной табличной переменной и возвращаемым значением функции):

Simple XML              NULL                  NULL
Wrapped with subquery   NULL                  NULL
XML column              NULL                  NULL
Casted XML              x                     xml
Wrapped Casted XML      wrapped               xml
Text value              text_string           ntext
Wrapped Text Value      text_string_wrapped   ntext

EDIT: было новое наблюдение, которое я считал неясным, но это была моя ошибка... Забрал его...

Comments

    Ничего не найдено.