Выберите для 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)
Вывод:
╔═══════════════════════╦═════════════════════════════════════════╦══════════════════╗
║ 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
Вопросы:
- Почему
FOR XML AUTOне возвращаетXML/NVARCHAR(MAX)тип данных, ноntext(устаревший тип данных!)? - как обертывание с подзапросом изменяет тип данных с
ntextнаnvarchar(max)? - Почему те же правила не применяются к столбцам
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 ║
╚════════════════════════╩═══════════════════════════════════════╩══════════════════╝
Согласно 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);
- Почему
ntextНеnvarchar(max)как в цитатеthe XML data comes back as a string typeи где разница нормальная / временная таблица?
2 ответов:
В SQL Server 2000 не было типов данных
FOR XMLбыл представлен в SQL Server 2000.MAXилиXML. Также невозможно было использоватьFOR XMLв подзапросе.Статья что возвращает серверная часть для XML? объясняет
В SQL Server 2000 ...
FOR XML... был реализовано в слое кода между процессором запросов и транспортный уровень данных ... обработчик запросов выдает результат так же, как и без него.FOR XMLи затем кодFOR XMLформатирует набор строк как XML. Для максимального XML publishing performanceFOR XMLвыполняет распаривание XML-форматирования результирующий набор строк и напрямую отправляет выходные данные на стороне сервера ТДС код в небольших кусках без буферизации всего XML в пространстве сервера. Размер блока составляет 2033 символа UCS-2. Таким образом, XML больше, чем 2033 Символы UCS-2 отправляются на клиентскую сторону в нескольких строках каждый содержащий часть XML-файла. SQL Server использует предопределенный столбец название для этого набор строк с одним столбцом типаNTEXT- "XML_F52E2B61-18A1-11d1-B105-00805F49916B– - для обозначения фрагментированного XML набор строк в кодировке UTF-16.Таким образом, похоже, что это все еще реализуется таким же образом для верхнего уровня
В SQL Server 2005 появилась возможность использоватьFOR XMLи в более поздних версиях.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 ntextEDIT: было новое наблюдение, которое я считал неясным, но это была моя ошибка... Забрал его...




Comments