sql-server - SQL 服务器 : Selective XML Index not being efficiently used

标签 sql-server xml performance sql-optimization

我正在探索提高应用程序性能的方法,我只能在有限程度上影响数据库级别。 SQL Server 版本是 2012 SP2 并且有问题的表和 View 结构是(我不能真正影响这个+注意 xml 文档可能总共有几百个元素):

CREATE TABLE Orders(
    id nvarchar(64) NOT NULL,
    xmldoc xml NULL,
    CONSTRAINT PK_Order_id PRIMARY KEY CLUSTERED (id)
);

CREATE VIEW V_Orders as
SELECT 
    a.id, a.xmldoc
    ,a.xmldoc.value('data(/row/c1)[1]', 'nvarchar(max)') "Stuff"
    ,a.xmldoc.value('data(/row/c2)[1]', 'nvarchar(max)') "OrderType"
etc..... many columns
from Orders a;

一个典型的查询(以及下面用于测试的查询):

SELECT id FROM V_Orders WHERE OrderType = '30791'

所有查询都是针对 View 执行的,我既不能影响查询也不能影响表/ View 结构。

我认为向表中添加一个选择性 XML 索引将是我的救星:

CREATE SELECTIVE XML INDEX I_Orders_OrderType ON Orders(xmldoc)
FOR(
    pathOrderType = '/row/c2' as SQL [nvarchar](20)
)

但即使在更新统计信息之后,执行计划看起来也很奇怪。无法将图片作为新帐户发布,因此相关详细信息作为文本:

  • 从 selectiveXml 中查找聚集索引(成本:占总数的 2%)。期望行数1但期望执行次数1269(表中行数)
  • -> Top N 排序(成本:总成本的 95%)
  • -> 计算标量(成本 0)

  • 单独分支:聚簇索引扫描 PK_Order_id(成本:总成本的 3%)。预期行数1269

  • -> 使用嵌套循环(左外连接)合并到计算机标量结果
  • ->过滤器
  • -> 最终结果(预期行数1269)

实际上,对于我的测试数据,查询甚至没有返回任何结果,但它是否返回一个或几个没有任何区别。执行时间支持查询真正花费的时间,只要可以从执行计划中推断出来并且读取计数为数千。

所以我的问题是为什么优化器没有正确使用选择性 xml 索引?还是我弄错了什么?我将如何使用选择性 xml 索引(或可能的持久列)优化此特定查询的性能?

编辑: 我用更大的样本数据(表中约 274k 行,XML 文档接近平均生产规模)做了额外的测试,并将选择性 XML 索引与提升的列进行了比较。结果来自 Profiler 跟踪,集中在 CPU 使用率和读取计数上。选择性 xml 索引的执行计划与上述内容基本相同。

选择性 XML 索引和 274k 行(执行上面的查询): CPU:6454,读取:938521

将搜索字段中的值更新为唯一值后(总记录数仍为 274k),我得到以下结果:

选择性 XML 索引和 274k 行(执行上面的查询): CPU:10077,读取:1006466

然后使用提升的(即持久化的)单独索引列并直接在 View 中使用它: CPU:0,读取:23

选择性 XML 索引性能似乎比正确的 SQL 索引列提取更接近全表扫描。我在某处读到,对表使用模式可能有助于从执行计划中删除 TOP N 步骤(假设我们正在搜索非重复字段),但我不确定在这种情况下这是否是现实的可能性。

最佳答案

您创建的选择性 XML 索引存储在一个内部表中,并将 Orders 中的主键作为内部表聚集键的前导列,并将指定的路径存储为稀疏列。

您获得的查询计划可能看起来像这样:

enter image description here

您对整个 Orders 表进行了扫描,并在内表中针对 Orders 中的每一行的主键进行查找。最后一个 Filter 运算符负责检查 OrderType 的值,仅返回匹配的行。

实际上并不是您对索引的期望。

辅助的选择性 XML 索引来拯救。它们是为主要选择性索引中指定的路径之一创建的,并将在路径表达式中提取的值上创建非聚集键。

然而,这并不是那么容易。 SQL Server 不会对用于 values() 函数提取的值的谓词使用二级索引。您必须改用 exists() 。此外,exists() 要求在路径表达式中使用 XQUERY 数据类型,而 value() 使用 SQL 数据类型。

您的主要选择性 XML 索引可能如下所示:

CREATE SELECTIVE XML INDEX I_Orders_OrderType ON Orders(xmldoc)
FOR 
(
  pathOrderType = '/row/c2' as sql nvarchar(20), 
  pathOrderTypeX = '/row/c2/text()' as xquery 'xs:string' maxlength (20)
)

pathOrderTypeX 上有辅助。

CREATE XML INDEX I_Orders_OrderType2 ON Orders(xmldoc)
  USING XML INDEX I_Orders_OrderType FOR (pathOrderTypeX) 

通过使用 exist() 的查询,您将获得此计划。

select id
from V_Orders
where xmldoc.exist('/row/c2/text()[. = "30791"]') = 1

enter image description here

第一次查找是查找您在内表的非聚集索引中查找的值。键查找是在内部表的聚集键上完成的(不知道为什么这是必要的)。最后一个搜索是在 Orders 表中的主键上,然后是一个过滤器,用于检查 xmldoc 列中的空值。

如果你可以使用 property promotion ,从 XML 在 Orders 表中创建计算索引列,我猜你仍然会比使用辅助选择性 XML 索引获得更好的性能。

关于sql-server - SQL 服务器 : Selective XML Index not being efficiently used,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30734379/

相关文章:

asp.net - ASP.NET 应用程序加载时间缓慢 - 我可以跟踪/追踪/计时整个加载周期吗?

sql - 使用变量的值更新行并在变量为空时使用默认值

python - ODBC DSN 使 MSSQL 减慢至超时

php - 在 PHP 上将多种类型的日期字符串格式化为相同的日期格式

c# - Entity Framework 在应用 Where 过滤器时是否选择内存中的所有行?

java - 视觉虚拟机中的采样

php - 使用 php 将数字添加到获取的数组中

java - ImageView不能像按钮一样被点击

xml - 如何在 Java 中使用 DOM 获取子节点

performance - 在 OCaml 模式匹配中哪个更好, `when` 或 `if-then-else` ?