web-dev-qa-db-ja.com

最も効果的なSELECTIVE XMLインデックスは何ですか?

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)

最も効率的なインデックスです:

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'
)

<OtherTag>内のLargeIrrelevantDataにインデックスを付けたくありません。

次のクエリを使用して、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

関連するいくつかの質問:

クエリの実行時間を確認する以外に、選択的インデックスのパフォーマンス向上を他にどのように判断できますか?

データ型を指定するときに、XQUERYのxs:doubleまたはSQLのINTを使用することは推奨されますか?

ありがとうございました。

5
Danny Rancher

クエリの実行時間を確認する以外に、選択的インデックスのパフォーマンス向上を他にどのように判断できますか?

IO使用率とCPUを確認することもできます。選択的なXMLインデックスを処理するときにおそらく最も興味深いのは、インデックスがクエリによって実際に使用されているかどうかを確認することです。そのために、実行計画で。

XMLの解析を担当するテーブル値関数の1つが表示された場合は、XMLクエリでXMLインデックスをカバーしていないことがわかります。

enter image description here

代わりに、XMLインデックスに使用される内部テーブルのスキャンまたはシーク演算子を用意する必要があります。

enter image description here

データ型を指定するときに、XQUERYのxs:doubleまたはSQLのINTを使用することは推奨されますか?

インデックスをvalue()関数に使用する場合は、インデックスのデータ型をクエリで使用されるデータ型と一致させる必要があります。クエリにnvarchar(max)があり、インデックスに_xs:double_があるため、_ChildTag1_および_ChildTag2_はクエリで使用されません。代わりに、テーブル値関数を使用して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
);
_

_ChildTag1_および_ChildTag2_のnode()インデックスはクエリで使用されないため、インデックスでは必要ありません。

_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);
_

最も効果的なSELECTIVE XMLインデックスは何ですか?

ユースケースとデータがどのように見えるかによって完全に異なります。この答えは、クエリを最適化しようとするものではなく、インデックスの使用方法を示す方法にすぎません。データをテストした結果、インデックスをまったく使用しないか、クエリの一部にのみインデックスを使用することで、最高のパフォーマンスが得られることがわかります。原則として、インデックスはできるだけ小さくすることをお勧めします。整数を扱うことがわかっている場合は、intの代わりにfloatを使用することをお勧めします。

8
Mikael Eriksson