设置:
create table dbo.T
(
ID int identity primary key,
XMLDoc xml not null
);
insert into dbo.T(XMLDoc)
select (
select N.Number
for xml path(''), type
)
from (
select top(10000) row_number() over(order by (select null)) as Number
from sys.columns as c1, sys.columns as c2
) as N;
每行的示例 XML:
<Number>314</Number>
查询的工作是计算T
具有指定值 的行数<Number>
。
有两种明显的方法可以做到这一点:
select count(*)
from dbo.T as T
where T.XMLDoc.value('/Number[1]', 'int') = 314;
select count(*)
from dbo.T as T
where T.XMLDoc.exist('/Number[. eq 314]') = 1;
事实证明,value()
和exists()
需要两个不同的路径定义才能使选择性 XML 索引起作用。
create selective xml index SIX_T on dbo.T(XMLDoc) for
(
pathSQL = '/Number' as sql int singleton,
pathXQUERY = '/Number' as xquery 'xs:double' singleton
);
sql
版本适用于版本适用value()
于.xquery
exist()
您可能认为这样的索引会给您一个很好的搜索计划,但选择性 XML 索引是作为系统表实现的,其主键是T
系统表聚集键的主键。指定的路径是该表中的稀疏列。如果您想要定义路径的实际值的索引,您需要创建一个二级选择性索引,每个路径表达式一个。
create xml index SIX_T_pathSQL on dbo.T(XMLDoc)
using xml index SIX_T for (pathSQL);
create xml index SIX_T_pathXQUERY on dbo.T(XMLDoc)
using xml index SIX_T for (pathXQUERY);
的查询计划exist()
在辅助 XML 索引中进行查找,然后在系统表中进行选择性 XML 索引的键查找(不知道为什么需要这样做),最后它进行查找T
以确保确实存在行在那里。最后一部分是必要的,因为系统表和T
.
查询计划value()
不是很好。它T
使用嵌套循环连接对内部表进行搜索以从稀疏列中获取值并最终过滤该值进行聚簇索引扫描。
是否应该使用选择性索引是在优化之前决定的,但是是否应该使用辅助选择性索引是优化器基于成本的决定。
为什么 where 子句过滤时不使用二级选择索引value()
?
更新:
查询在语义上是不同的。如果您添加一行值
<Number>313</Number>
<Number>314</Number>`
该exist()
版本将计算 2 行,而values()
查询将计算 1 行。但是使用singleton
指令 SQL Server 将在此处指定的索引定义阻止您添加包含多个<Number>
元素的行。
但是,这不允许我们在values()
不指定的情况下使用该函数,[1]
以保证编译器我们只会获得一个值。这[1]
就是我们在value()
计划中采用 Top N 排序的原因。
看起来我正在接近这里的答案......
索引的路径表达式中的声明
singleton
强制您不能添加多个元素,但 XQuery 编译器在解释函数<Number>
中的表达式时不会考虑到这一点。value()
您必须指定[1]
才能让 SQL Server 满意。将类型化 XML 与模式一起使用也无济于事。正因为如此,SQL Server 构建了一个使用可称为“应用”模式的东西的查询。最容易演示的是使用常规表而不是 XML 来模拟我们实际执行的查询
T
和内部表。这是内部表作为真实表的设置。
两个表都准备就绪后,您可以执行与
exist()
查询等效的操作。查询的等效项
value()
如下所示。top(1)
and是罪魁祸首,order by S.path_1_id
它[1]
在 Xpath 表达式中是罪魁祸首。我认为 Microsoft 不可能用内部表的当前结构修复此问题,即使您被允许
[1]
从values()
函数中省略。他们可能必须为每个具有唯一约束的路径表达式创建多个内部表,以向优化器保证每一行只能有一个<number>
元素。不确定这是否足以让优化器“打破应用模式”。对于那些认为这很有趣和有趣的人,并且由于您仍在阅读本文,所以您可能是。
一些查询要看内表的结构。