(This is an updated repost from earlier this year on my old blog) Whenever I’m discussing index maintenance, and specifically fragmentation, I always make a point of saying ‘Make sure the index is being used before doing anything about fragmentation’. If an index isn’t being used very much, but has very low page density (lots of free space in the index pages), then it will be occupying a lot more disk space than it could do and it may be worth compacting (with a rebuild or a defrag) to get that disk space back. However, usually there’s not much point spending resources to remove any kind of fragmentation when an index isn’t being used. This is especially true of those people who rebuild all indexes every night or every week. You could even go so far as to say if a non-clustered index isn’t being used, why is it there at all? Extra non-clustered indexes drag down performance in a number of ways. Consider a non-clustered index called IX_MyNCIndex on the table MyTable: That’s a significant amount of extra IOs and log records to maintain each extraneous non-clustered index. So, how can you tell if an index is being used? This DMV exposes the information that is tracked about index usage (as the name suggests). It does not generate any information itself; it just returns info from a cache inside SQL Server. This cache is empty when the server instance starts, and is not persisted across instance restarts. All cache entries for indexes in a database are removed when that database is closed. So, the cache tracks usage information about which indexes have been used since the database they are part of was last opened (either manually or as part of instance start-up). This continues to confuse people so I’ll call it out: if the output from the DMV does not have an entry for the index you’re interested in, it has not been used since the last database startup. The cache tracks the following info for each index (for user queries and system queries): Let’s have a look at its use. SELECT GO The output is too wide for a single image so I’ve split it in two (I won’t post any more output from the DMV – I’ll just talk about it): Unless you’ve just re-started your instance, you’ll see a bunch of output from this, representing all index activity since the instance/databases started. If you’re interested in whether an index is being used, you can filter the output. Let’s focus in on a particular table – AdventureWorks.Person.Address. SELECT WHERE AND GO You’ll probably see nothing in the output, unless you’ve been playing around with that table. Let’s force the clustered index on that table to be used, and look at the DMV output again. SELECT GO SELECT WHERE AND GO Now there’s a single row, showing a scan on the clustered index. Let’s do something else. SELECT WHERE GO SELECT WHERE AND GO And there’s another row, showing a seek in one of the table’s non-clustered indexes. So, its easy to look at the index usage for particular tables and indexes. But how can you monitor this over time? This is easy too – let’s see how. First we need to create our own table to store snapshots of the DMV output. IF GO SELECT FROM GO Next we need to take a baseline snapshot of the DMV output. INSERT GO And now simulate a few operations and take another snapshot of the DMV: SELECT GO SELECT GO SELECT WHERE GO INSERT GO And look at the filtered contents of our snapshot table: SELECT WHERE AND GO You should see four rows – two from the baseline snapshot and two from the final snapshot. If you ran just the statements above, you’ll see that the user_scans count for the clustered index has increased by two, and the user_seeks count for the non-clustered index has increased by one. So this is a pretty simple example of how you can track index usage. By putting something like this into a regularly run script you can tell which indexes aren’t being used and could be candidates for less-regular index maintenance or removal altogether. Let me know how you get on.
* FROM sys.dm_db_index_usage_stats;


* FROM sys.dm_db_index_usage_stats
database_id = DB_ID(‘AdventureWorks’)
* FROM AdventureWorks.Person.Address;
database_id = DB_ID(‘AdventureWorks’)
StateProvinceID FROM AdventureWorks.Person.Address
StateProvinceID > 4 AND StateProvinceId < 15;
database_id = DB_ID(‘AdventureWorks’)
OBJECTPROPERTY (object_id (N‘master.dbo.MyIndexUsageStats’), ‘IsUserTable’) = 1 DROP TABLE dbo.MyIndexUsageStats;
sys.dm_db_index_usage_stats WHERE database_id=0;
master.dbo.MyIndexUsageStats
SELECT getdate (), * FROM sys.dm_db_index_usage_stats;
* FROM AdventureWorks.Person.Address;
SELECT getdate (), * FROM sys.dm_db_index_usage_stats;
* FROM master.dbo.MyIndexUsageStats
7 Responses to Indexes From Every Angle: How can you tell if an index is being used?
I’m amazed noone has posted this yet. Here’s something awesome you can do with this: Get a list of all your indexes and how used / unused they are.
I’ve got a db that is heavily used with db_id = 5. This query shows me all the indexes that are in that database, and sorts the list by usage of those indexes. This shows you heaps (index_name = null) and unused indexes (where user_* and system_* are 0 or very small) or indexes that are just a tax on the system (ie, never queried against, only updated). This doesn’t mean that those indexes should be deleted – they might just have little use – but it’s a good start, and gets better the longer your db is up. Anyways, on with the query!
SELECT object_name(b.object_id) as obj_name, b.name as index_name, a.*
FROM sys.dm_db_index_usage_stats a
right outer join sys.indexes b on a.object_id = b.object_id and a.index_id = b.index_id and a.database_id = 5
where b.object_id > 100
order by user_seeks + user_scans
Hope others find that useful :)
索引不嫌多
This code is very helpful. I am working on Index maintainence strategy for a DB where indexes have never been rebuild/re-organised. I was looking at fragmentation levels of current indexes where I came across this topic and makes lot of sense to get rid of non-used indexes or atleast keep them out of your indexing strategy since its not been used.
Thanks
Kishore
This is awesome!
thanks,
Jeet
[...] Paul's blog: Indexes From Every Angle: How can you tell if an index is being used? [...]
[...] And, if you want to get a few more insghts into how to persist this on Paul's blog here: http://www.sqlskills.com/blogs/PAUL/post/Indexes-From-Every-Angle-How-can-you-tell-if-an-index-is-be…. [...]
[...] DMV to find indexes that are only being updated. I've blogged about this here. Again, be careful though. Just because an index hasn't been used doesn't mean it should be [...]