什么是最有效的 SELECTIVE XML 索引?

Dan*_*her 6 performance index xml sql-server query-performance

我正在尝试为 1 亿行表中的 XML 列确定最有效的选择性 XML 索引。我的问题类似于:

用于选择性 Xml 索引的 Sql Server 2012 扩展事件未显示结果

但是答案中指定的选择性索引的具体好处没有详细讨论。

以下是查询的简化版本:

;WITH CTE AS
( SELECT 1 AS ID,
              CONVERT(XML, '<Root>
                              <ParentTag ParentTagID="Sample Text">
                                <ChildTag1>5</ChildTag1>
                                <ChildTag1>6</ChildTag1>
                                <ChildTag1>7</ChildTag1>
                                <ChildTag2>8</ChildTag2>
                                <ChildTag2>9</ChildTag2>
                                <ChildTag2>10</ChildTag2>
                                <OtherTag>LargeIrrelevantData</OtherTag>
                              </ParentTag>
                            </Root>'
                      ) AS SampleXML
)
SELECT * INTO dbo.CTE FROM CTE

SELECT ID,
       Root.ParentTag.value('@ParentTagID','NVARCHAR(MAX)') AS ParentTagID,
       RootParentTag1.ChildTag1.value('(text())[1]', 'NVARCHAR(MAX)') AS ChildTag1,
       NULL
FROM CTE
OUTER APPLY CTE.SampleXML.nodes('/Root/ParentTag') as Root(ParentTag)
OUTER APPLY Root.ParentTag.nodes('ChildTag1') as RootParentTag1(ChildTag1)
UNION
SELECT ID,
       Root.ParentTag.value('@ParentTagID','NVARCHAR(MAX)') AS ParentTagID,
       NULL,
       RootParentTag2.ChildTag2.value('(text())[1]', 'NVARCHAR(MAX)') AS ChildTag2
FROM CTE
OUTER APPLY CTE.SampleXML.nodes('/Root/ParentTag') as Root(ParentTag)
OUTER APPLY Root.ParentTag.nodes('ChildTag2') as RootParentTag2(ChildTag2)
Run Code Online (Sandbox Code Playgroud)

是最有效的索引:

EXEC sp_db_selective_xml_index [DATABASE], TRUE
ALTER TABLE CTE ADD CONSTRAINT PK_CTE PRIMARY KEY CLUSTERED (ID)

CREATE SELECTIVE XML INDEX SIX_CTE ON CTE(SampleXML)
FOR
( ParentTag = '/Root/ParentTag' AS XQUERY 'node()',
  ParentTagChildTag1 = '/Root/ParentTag/ChildTag1' AS XQUERY 'node()',
  ParentTagChildTag2 = '/Root/ParentTag/ChildTag2' AS XQUERY 'node()',
  ParentTagID = '/Root/ParentTag/@ParentTagID' AS XQUERY 'xs:string' MAXLENGTH(255),
      ChildTag1 = '/Root/ParentTag/ChildTag1/text()' AS XQUERY 'xs:double',
      ChildTag2 = '/Root/ParentTag/ChildTag2/text()' AS XQUERY 'xs:double'
)
Run Code Online (Sandbox Code Playgroud)

我不希望LargeIrrelevantData, 内的<OtherTag>, 被索引。

我正在使用以下查询来跟踪 XML 中的索引列

SELECT
a.name AS column_name,
c.name AS data_type
FROM sys.columns a
INNER JOIN sys.indexes b
ON a.object_id = b.object_id
INNER JOIN sys.types c
ON a.system_type_id = c.user_type_id
WHERE b.name = 'SIX_CTE'
AND b.type = 1
ORDER BY column_id
Run Code Online (Sandbox Code Playgroud)

几个相关的问题:

除了查看查询执行时间之外,我还能如何确定选择性索引的性能提升?

在指定数据类型时,是首选使用 XQUERY 的 xs:double 还是 SQL 的 INT?

谢谢你。

Mik*_*son 8

除了查看查询执行时间之外,我还能如何确定选择性索引的性能提升?

您还可以查看 IO 利用率和 CPU。处理选择性 XML 索引时最有趣的可能是弄清楚查询是否实际使用了索引。为此,您可以查看执行计划。

如果您看到负责解析 XML 的表值函数之一,那么您就知道您没有使用 XML 索引覆盖您的 XML 查询。

在此处输入图片说明

相反,您应该在用于 XML 索引的内部表上使用扫描或查找运算符。

在此处输入图片说明

在指定数据类型时,是首选使用 XQUERY 的 xs:double 还是 SQL 的 INT?

如果您希望将索引用于value()函数,您应该将索引中的数据类型与查询中使用的数据类型相匹配。您nvarchar(max)在查询和xs:double索引中都有ChildTag1ChildTag2因此未在您的查询中使用。相反,它使用表值函数解析 XML 数据。

要使您的查询仅使用索引(无 xml 解析函数),您可以将查询和索引更改为此。

create selective xml index SIX_CTE on CTE(SampleXML) for
(
  ParentTag = '/Root/ParentTag' as xquery 'node()',
  ParentTagID = '/Root/ParentTag/@ParentTagID' as sql nvarchar(255),
  ChildTag1 = '/Root/ParentTag/ChildTag1' as sql int,
  ChildTag2 = '/Root/ParentTag/ChildTag2' as sql int
);
Run Code Online (Sandbox Code Playgroud)

请注意,您的查询不使用和上的node()索引,因此索引中不需要。ChildTag1ChildTag2

SELECT ID,
       Root.ParentTag.value('@ParentTagID','NVARCHAR(255)') AS ParentTagID,
       RootParentTag1.ChildTag1.value('.', 'INT') AS ChildTag1,
       NULL
FROM CTE
OUTER APPLY CTE.SampleXML.nodes('/Root/ParentTag') as Root(ParentTag)
OUTER APPLY Root.ParentTag.nodes('ChildTag1') as RootParentTag1(ChildTag1)
UNION
SELECT ID,
       Root.ParentTag.value('@ParentTagID','NVARCHAR(255)') AS ParentTagID,
       NULL,
       RootParentTag2.ChildTag2.value('.', 'INT') AS ChildTag2
FROM CTE
OUTER APPLY CTE.SampleXML.nodes('/Root/ParentTag') as Root(ParentTag)
OUTER APPLY Root.ParentTag.nodes('ChildTag2') as RootParentTag2(ChildTag2);
Run Code Online (Sandbox Code Playgroud)

什么是最有效的 SELECTIVE XML 索引?

完全取决于您的用例以及您拥有的数据。这个答案绝不是试图优化您的查询,只是向您展示如何使用索引的一种方式。对您的数据进行测试的结果可能表明,通过根本不使用任何索引或仅在查询的某些部分使用索引,您可以获得最佳性能。作为一般规则,保持索引尽可能小总是好的,因此如果您知道要处理整数intfloat则使用代替是一件好事。