How do I track the usage of XML indexes?
-
16-10-2019 - |
Question
My XML indexes are not listed in sys.dm_db_index_usage_stats
Does this mean they aren't being used? Or does this particular DMV not track XML index usage? (Books Online doesn't appear to answer the question)
If they aren't being tracked by sys.dm_db_index_operational_stats
, is there another way to know how much they are being used, or what cached plans currently use them?
Solution
I tried to reproduce what you're experiencing and couldn't make it happen, unfortunately (see the second part of this answer). If this was a bugfix between versions, it was pretty well undocumented: running this through Google produced absolutely nothing.
I suspect the problem is that the analysis query you're running is joining sys.dm_db_index_usage_stats
to sys.tables
. Sounds reasonable, except XML indexes don't have the same relationship to their base table as regular clustered and nonclustered indexes do.
The way XML indexes work, the indexes aren't created against the base table at all. Creating a primary XML index materializes (i.e., creates a clustered index of) the node table that gets generated from the XML data; secondary indexes are nonclustered indexes on the node table. Okay, fine, so what? The catch is that the materialized node table is an internal table, and does not appear in sys.tables
(have a look in sys.internal_tables
instead). So you can see why you won't get rows back for those indexes at all unless all the rows from the DMV are getting returned with an OUTER JOIN
in the query (and even then, you won't directly get a name for the table in that row).
To be honest, I only recently learned how XML indexes work, so I actually have to go back and revisit my own index analysis scripts as well (I suspect they have this exact flaw). Here's a quick base script I whipped together that should correct the problem:
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
This was run against my local instance (64-bit Developer edition, 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
and got these results:
Note how the object_id
of the primary and secondary XML indexes is different than the object_id
of the table's clustered index.
OTHER TIPS
The following query shows all cached plans that contain a specific string:
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%'
Since I found cached plans that contained the name of the XML index, I'm reasonably certain the indexes are being used. That implies, then, that sys.dm_db_index_usage_stats
does not, in fact, track usage of XML indexes.
If anyone can find any links to support/refute this, that would be appreciated.