web-dev-qa-db-ja.com

XMLインデックスの使用状況を追跡するにはどうすればよいですか?

私のXMLインデックスはsys.dm_db_index_usage_statsにリストされていません

これは、それらが使用されていないことを意味しますか?または、この特定のDMVはXMLインデックスの使用を追跡しませんか? (Books Onlineは質問に答えていないようです)

それらがsys.dm_db_index_operational_statsによって追跡されていない場合、それらがどれだけ使用されているか、または現在どのキャッシュプランがそれらを使用しているかを知る別の方法はありますか?

4
BradC

私はあなたが経験していることを再現しようとしましたが、残念ながらそれを実現できませんでした(この回答の2番目の部分を参照してください)。これがバージョン間のバグ修正である場合、それはかなり文書化されていませんでした。これをGoogleで実行しても、まったく何も生成されませんでした。

問題は、実行している分析クエリがsys.dm_db_index_usage_statssys.tablesに結合していることだと思います。 XMLインデックスは、通常のクラスター化インデックスおよび非クラスター化インデックスと同じ関係をベーステーブルと持たないことを除けば、合理的に聞こえます。

XMLインデックスが機能する方法では、インデックスはベーステーブルに対してまったく作成されません。プライマリXMLインデックスを作成すると、XMLデータから生成されるノードテーブルが具体化されます(つまり、クラスター化されたインデックスが作成されます)。セカンダリインデックスは、ノードテーブルの非クラスター化インデックスです。いいでしょういいので何ですかキャッチは、マテリアライズドノードテーブルが内部テーブルであり、sys.tablesに表示されないことです(代わりにsys.internal_tablesを参照してください)。したがって、DMVからのすべての行がクエリでOUTER JOINを使用して返されない限り、これらのインデックスの行がまったく返されない理由がわかります(それでも、名前を直接取得することはできません)。その行のテーブルの場合)。

正直なところ、私はXMLインデックスがどのように機能するかを最近知ったばかりなので、実際に戻って自分のインデックス分析スクリプトも再検討する必要があります(これらにはこの正確な欠陥があると思われます)。これは、問題を修正するために一緒に作成した簡単な基本スクリプトです。

SELECT
    OBJECT_NAME(COALESCE(t.object_id, t2.object_id)) AS TableName,
    i.name AS IndexName,
    us.*
    FROM sys.dm_db_index_usage_stats us
    INNER JOIN sys.indexes i ON i.object_id = us.object_id AND i.index_id = us.index_id
    LEFT OUTER JOIN sys.tables t ON t.object_id = us.object_id
    LEFT OUTER JOIN sys.internal_tables it ON it.object_id = us.object_id
    LEFT OUTER JOIN sys.tables t2 ON t2.object_id = it.parent_object_id

これは私のローカルインスタンス(64ビットDeveloperエディション、10.50.1617)に対して実行されました:

CREATE TABLE XmlIndexTest
(
    Id int IDENTITY(1, 1) NOT NULL,
    Data xml NOT NULL,

    CONSTRAINT PK_XmlIndexTest
        PRIMARY KEY CLUSTERED(Id)
)
GO

INSERT INTO XmlIndexTest(Data)
    VALUES('<Invoice><LineItem Id="1" /></Invoice>')

CREATE PRIMARY XML INDEX IX_PrimaryXml ON XmlIndexTest(Data)

SELECT *
    FROM XmlIndexTest
    WHERE Data.exist('/Invoice/LineItem[@Id = 1]') = 1

SELECT i.name, us.*
    FROM sys.dm_db_index_usage_stats us
    INNER JOIN sys.indexes i ON i.object_id = us.object_id AND i.index_id = us.index_id

CREATE XML INDEX IX_SecondaryXml ON XmlIndexTest(Data)
    USING XML INDEX IX_PrimaryXml FOR PATH

SELECT *
    FROM XmlIndexTest
    WHERE Data.exist('/Invoice/LineItem[@Id = 1]') = 1

SELECT i.name, us.*
    FROM sys.dm_db_index_usage_stats us
    INNER JOIN sys.indexes i ON i.object_id = us.object_id AND i.index_id = us.index_id

そしてこれらの結果を得ました:

enter image description here

プライマリおよびセカンダリXMLインデックスのobject_idが、テーブルのクラスタ化インデックスのobject_idとどのように異なるかに注意してください。

3
Jon Seigel

次のクエリは、特定の文字列を含むすべてのキャッシュされたプランを示しています。

WITH _a AS (
    SELECT *
    FROM sys.dm_exec_cached_plans _cp
    WHERE EXISTS (
        SELECT *
        FROM sys.dm_exec_plan_attributes(_cp.plan_handle) _pa
        WHERE _pa.attribute = 'dbid' 
        AND value = DB_ID('MR_ARG_Ford')
                  )
    )
SELECT OBJECT_NAME(objectid), *
FROM _a
CROSS APPLY sys.dm_exec_query_plan(_a.plan_handle)
WHERE convert(nvarchar(max), query_plan) like '%Name_of_your_XML_Index%'

XMLインデックスの名前を含むキャッシュされたプランを見つけたので、インデックスが使用されていることはかなり確実です。つまり、sys.dm_db_index_usage_statsは、実際にはXMLインデックスの使用状況を追跡しません。

誰かがこれを支持/反論するためのリンクを見つけることができれば、それはありがたいです。

0
BradC