在玩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 ║
╚════════════════════════╩═══════════════════════════════════════╩══════════════════╝
SQL Server对xml(Transact-SQL)的支持使您可以选择 请求通过指定TYPE指令将FOR XML查询的结果作为xml数据类型返回。
SQL Server将XML数据类型实例数据作为a返回给客户端 不同服务器结构的结果,例如使用的FOR XML查询 TYPE指令,或使用xml数据类型返回XML的位置 SQL表列和输出参数中的实例数据值。在 客户端应用程序代码,ADO.NET提供程序请求此XML数据 键入要从服务器以二进制编码发送的信息。 但是,如果您使用的是没有TYPE指令的FOR XML,则为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
ntext
不是nvarchar(max)
,而是引用the XML data comes back as a string type
以及差异正常/临时表在哪里?答案 0 :(得分:6)
FOR XML
是在SQL Server 2000中引入的。
SQL Server 2000没有MAX
数据类型或XML
数据类型。也不可能在子查询中使用FOR XML
。
文章What does server side FOR XML return?解释
在SQL Server 2000中......
FOR XML
...是 在查询处理器和之间的代码层中实现 数据传输层...查询处理器以与没有相同的方式产生结果FOR XML
然后FOR XML
代码将行集格式化为XML。最大化 XML发布性能FOR XML
确实使用XML格式化 结果行集并直接将其输出发送到服务器端TDS 小块中的代码,无需在服务器空间中缓冲整个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代码,但“unwrapped”版本在计划本身中没有任何XML迭代器,结果是通过将CXStmtSelect
的方法调用替换为CXStmtXMLSelect
来实现的。相反(在计划中表示为XML Select根节点而不是普通的旧选择)。
在SQL Server 2016 CTP3上,我仍然看到ntext
为顶级FOR XML
。但是,顶级FOR JSON
显示为nvarchar(max)
至少在CTP中,JSON特殊列名仍然包含GUID F52E2B61-18A1-11d1-B105-00805F49916B
,尽管它的来源是the IXMLDocument Interface。
虽然XML Select被替换为JSON Select
,但计划看起来大致相同顺便说一句:在构建Microsoft SQL Server 2014 - 12.0.4213.0 (X64)
上,我发现临时表和永久表之间的行为没有任何区别。这可能取决于您的问题使用http://sqlfiddle.com/(12.0.2000.8)和https://data.stackexchange.com/(12.0.4213.0)的环境之间的不同@@Version
。
在2014年的两个版本中,sys.dm_exec_describe_first_result_set
可能修复了一个错误。
2012年,我在11.0.5343.0获得了与Shnugo相同的结果(前三行中有NULL
),但在安装SP3 11.0.6020.0后,我得到的结果与问题中显示的初始结果相同。 / p>
答案 1 :(得分:0)
有趣的问题! NTEXT
真的很奇怪!
我对子查询有所了解:当你返回一个XML时,它会被转换为字符串,除非你指定TYPE
(你肯定从嵌套的XML中用CROSS APPLY或者用STUFF的字符串连接知道这一点,你在某些地方看到这个TYPE
和.value()
- 有时&#34;裸体&#34;。
我无法真正重现您的结果(SQL Server 2012)。简单的复制&#39; n&#39;粘贴回来(我想用声明的表变量测试并返回函数的值):
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
编辑:有一个我认为不清楚的新观察,但这是我的错误......把它拿走了......