{"id":82010,"date":"2007-04-15T14:58:09","date_gmt":"2007-04-15T14:58:09","guid":{"rendered":"https:\/\/www.webstaging.red-gate.com\/simple-talk\/?p=73145"},"modified":"2018-12-12T13:43:25","modified_gmt":"2018-12-12T13:43:25","slug":"dynamic-management-function-query-to-view-index-usage","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/dynamic-management-function-query-to-view-index-usage\/","title":{"rendered":"Dynamic management function query to view index usage"},"content":{"rendered":"<p>Last week, I presented a query to <a href=\"http:\/\/drsql.spaces.live.com\/blog\/cns!80677FB08B3162E4!1606.entry\" target=\"_blank\">view I\/O pressure<\/a>, and (to me) more usefully, look at it in a slice of time, like when doing a performance test.&nbsp;  <\/p>\n<p>Here is a a very similar solution for index usage using the sys.dm_db_index_usage_stats dynamic management views. I will probably do several more of these types of blogs, as there is some really useful information in the dynamic management views, but the ones that start when the server is reset are troublesome when doing specific, time windowed performance tuning, something I am working on pretty heavy for the next week or so.&nbsp; (I mentioned this dmv a while back in <a href=\"http:\/\/drsql.spaces.live.com\/blog\/cns!80677FB08B3162E4!1443.entry\" target=\"_blank\">my blog here<\/a>, referring to this Microsoft SQL Server Development Customer Advisory Team blog entry on <a href=\"http:\/\/blogs.msdn.com\/sqlcat\/archive\/2006\/02\/13\/531339.aspx\" target=\"_blank\">index evaluation<\/a> and <a href=\"http:\/\/sqlservercode.blogspot.com\/2006\/09\/sysdmdbindexusagestats.html\" target=\"_blank\">a nice blog<\/a> on Denis&#8217; <a href=\"http:\/\/sqlservercode.blogspot.com\/\" target=\"_blank\">sqlservercode.blogspot.com<\/a> blog too.)  <\/p>\n<p>This script will build a temp table of the results from sys.dm_db_index_usage_stats (user stats only), and the current time.&nbsp; The @resetBaseLine variable is there to drop and recreate the #baseline table.&nbsp; It works only in the current database (the sys.dm_db_index_usage_stats dmv works in any database, but sys.indexes will not.)  <\/p>\n<p>declare @resetbaseLine bit, @dbname sysname<br \/>set @resetbaseLine =1<br \/>declare @dbid int <br \/>select @dbid = db_id()<br \/>set nocount on<br \/>if @resetBaseLine = 1 or object_id(&#8216;tempdb..#baseline&#8217;) is null<br \/>&nbsp;&nbsp;&nbsp; begin<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if object_id(&#8216;tempdb..#baseline&#8217;) is not null<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drop table #baseline<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select object_name(i.object_id) as object_name<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , i.object_id <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , i.name as index_name<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , case when i.is_unique = 1 then &#8216;UNIQUE &#8216; else &#8221; end + i.type_desc as index_type<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , i.index_id <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , coalesce(user_seeks,0) as user_seeks<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , coalesce(user_scans,0) as user_scans <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , coalesce(user_lookups,0) as user_lookups<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , coalesce(user_updates,0) as user_updates<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , getdate() as baselineDate<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; into #baseline<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; from sys.indexes i <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; left outer join sys.dm_db_index_usage_stats s <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; on i.object_id = s.object_id <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; and i.index_id = s.index_id <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; and database_id = @dbid&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where objectproperty(i.object_id , &#8216;IsUserTable&#8217;) = 1 <br \/>&nbsp;&nbsp;&nbsp; end <\/p>\n<p>select&nbsp;&nbsp; #baseline.object_name, #baseline.index_name, #baseline.index_type<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , currentLine.user_seeks &#8211; #baseline.user_seeks as user_seeks<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , currentLine.user_scans &#8211; #baseline.user_scans as user_scans<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , currentLine.user_lookups &#8211; #baseline.user_lookups as user_lookups<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , currentLine.user_updates &#8211; #baseline.user_updates as user_updates<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , case when last_user_seek &gt;= #baseline.baselineDate then last_user_seek else null end <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; as last_user_seek<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , case when last_user_scan &gt;= #baseline.baselineDate then last_user_scan else null end <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; as last_user_scan<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , case when last_user_lookup &gt;= #baseline.baselineDate then last_user_lookup else null end <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; as last_user_lookup<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , case when last_user_update &gt;= #baseline.baselineDate then last_user_update else null end <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; as last_user_update<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , dateDiff(second,#baseline.baselineDate,getdate()) as seconds_since_baseline<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , dateDiff(minute,#baseline.baselineDate,getdate()) as minutes_since_baseline<br \/>from #baseline<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; left join ( select s.object_id&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;, s.index_id <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , user_seeks <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , user_scans <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , user_lookups <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , user_updates <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , last_user_seek<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , last_user_scan<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , last_user_lookup<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , last_user_update<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; from sys.dm_db_index_usage_stats s <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; where database_id = @dbid <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; and objectproperty(s.object_id , &#8216;IsUserTable&#8217;) = 1 ) as currentLine<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; on #baseline.object_id = currentLine.object_id<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; and #baseline.index_id = currentLine.index_id<br \/>order by ( currentLine.user_seeks &#8211; #baseline.user_seeks + <br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; currentLine.user_scans &#8211; #baseline.user_scans +<br \/>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; currentLine.user_lookups &#8211; #baseline.user_lookups +&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentLine.user_updates &#8211; #baseline.user_updates ) desc <\/p>\n<blockquote><\/blockquote>\n<p>Here is a summary of what the different output columns mean:<\/p>\n<ul>\n<li><strong>object_name&nbsp;<\/strong>&#8211; the table or view that has the index\n<li><strong>index_name <\/strong>&#8211; the name of the index\n<li><strong>index_type <\/strong>&#8211; type of index, whether it is unique or not, and if it is clustered, heap, or nonclustered\n<li><strong>user_seeks <\/strong>&#8211; number of seeks for a particular key caused by user queries\n<li><strong>user_scans <\/strong>&#8211; number of scans through an index&#8217;s leaf nodes caused by user queries\n<li><strong>user_lookups <\/strong>&#8211; number of key lookups caused by user queries\n<li><strong>user_updates <\/strong>&#8211; number of modifications caused by user queries\n<li><strong>last_user_seek <\/strong>&#8211; last time the&nbsp;index was&nbsp;used in a seek\n<li><strong>last_user_scan <\/strong>&#8211; last time the&nbsp;index was&nbsp;scanned in a user query<br \/><strong>last_user_lookup&nbsp;<\/strong>&#8211; last time the&nbsp;clustered index was&nbsp;to lookup an individual row from a non-clustered index seek.&nbsp; This information validated from Chris Hedgate&#8217;s blog entry: <a href=\"http:\/\/www.hedgate.net\/articles\/2006\/01\/30\/index-lookups-seeks-and-scans\" target=\"_blank\">Index Lookups, Seeks, and Scans<\/a>.)\n<li><strong>last_user_update <\/strong>&#8211; last time the&nbsp;index modified by a user query.<\/li>\n<\/ul>\n<p>Crossposted to:&nbsp;<a href=\"http:\/\/drsql.spaces.live.com\">http:\/\/drsql.spaces.live.com<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week, I presented a query to view I\/O pressure, and (to me) more usefully, look at it in a slice of time, like when doing a performance test.&nbsp; Here is a a very similar solution for index usage using the sys.dm_db_index_usage_stats dynamic management views. I will probably do several more of these types of&#8230;&hellip;<\/p>\n","protected":false},"author":56085,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[],"coauthors":[19684],"class_list":["post-82010","post","type-post","status-publish","format-standard","hentry","category-blogs"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82010","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/56085"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=82010"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82010\/revisions"}],"predecessor-version":[{"id":82390,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/82010\/revisions\/82390"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=82010"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=82010"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=82010"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=82010"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}