Skip to content

Indexing DMVs

A collection of queries covering the indexing DMVs: operational stats, usage stats, fragmentation and missing index recommendations.

Published Feb 7, 2010

Are your indexes healthy, used, or missing? This collection covers five DMVs. The operational-stats query shows leaf insert/update/delete counts per index; the two usage-stats queries show seeks/scans/lookups/updates - one plain, one pivoted so each index's key columns line up side by side for quick eyeballing; the fragmentation section runs sys.dm_db_index_physical_stats at all three modes (Limited, Sampled, Detailed) plus a sorted report of the worst offenders; and the final query joins the three missing-index DMVs to surface the optimizer's index suggestions with their expected benefit.

/*
sys.dm_db_index_operational_stats
sys.dm_db_index_usage_stats
sys.dm_db_index_physical_stats 
sys.dm_db_missing_index_details
sys.dm_db_missing_index_groups
sys.dm_db_missing_index_group_stats
*/



-------------------------------
-- Get index operational stats - tip 1239
-------------------------------
SELECT OBJECT_NAME(A.[OBJECT_ID]) AS [OBJECT NAME], 
       I.[NAME] AS [INDEX NAME], 
       A.LEAF_INSERT_COUNT, 
       A.LEAF_UPDATE_COUNT, 
       A.LEAF_DELETE_COUNT 
FROM   SYS.DM_DB_INDEX_OPERATIONAL_STATS (NULL,NULL,NULL,NULL ) A 
       INNER JOIN SYS.INDEXES AS I 
         ON I.[OBJECT_ID] = A.[OBJECT_ID] 
            AND I.INDEX_ID = A.INDEX_ID 
WHERE  OBJECTPROPERTY(A.[OBJECT_ID],'IsUserTable') = 1


-- Get index usage stats - tip 1239
-------------------------------
SELECT   OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], 
         I.[NAME] AS [INDEX NAME], 
         USER_SEEKS, 
         USER_SCANS, 
         USER_LOOKUPS, 
         USER_UPDATES 
FROM     SYS.DM_DB_INDEX_USAGE_STATS AS S 
         INNER JOIN SYS.INDEXES AS I 
           ON I.[OBJECT_ID] = S.[OBJECT_ID] 
              AND I.INDEX_ID = S.INDEX_ID 
WHERE    OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1 



-------------------------------
-- Get index usage stats - tip 1545
-------------------------------
SELECT db_name(), PVT.SCHEMANAME, PVT.TABLENAME, PVT.INDEXNAME, PVT.INDEX_ID, [1] AS COL1, [2] AS COL2, [3] AS COL3, 
       [4] AS COL4,  [5] AS COL5, [6] AS COL6, [7] AS COL7, B.USER_SEEKS, 
       B.USER_SCANS, B.USER_LOOKUPS, b.user_updates , C.ROWS 
FROM   (SELECT A.NAME AS TABLENAME, SCHEMA_NAME (a.schema_id) as SCHEMANAME,
               A.OBJECT_ID, 
               B.NAME AS INDEXNAME, 
               B.INDEX_ID, 
               D.NAME AS COLUMNNAME, 
               C.KEY_ORDINAL
        FROM   SYS.OBJECTS A 
               INNER JOIN SYS.INDEXES B 
                 ON A.OBJECT_ID = B.OBJECT_ID 
               LEFT JOIN SYS.INDEX_COLUMNS C 
                 ON B.OBJECT_ID = C.OBJECT_ID 
                    AND B.INDEX_ID = C.INDEX_ID 
               LEFT JOIN SYS.COLUMNS D 
                 ON C.OBJECT_ID = D.OBJECT_ID 
                    AND C.COLUMN_ID = D.COLUMN_ID 
        WHERE  A.TYPE = 'U') P 
       PIVOT 
       (MIN(COLUMNNAME) 
        FOR KEY_ORDINAL IN ( [1],[2],[3],[4],[5],[6],[7] ) ) AS PVT 
       LEFT JOIN SYS.DM_DB_INDEX_USAGE_STATS B 
         ON PVT.OBJECT_ID = B.OBJECT_ID 
            AND PVT.INDEX_ID = B.INDEX_ID 
            AND B.DATABASE_ID = DB_ID() 
	   LEFT JOIN SYS.SYSINDEXES C
		 ON PVT.OBJECT_ID = C.ID
			AND PVT.INDEX_ID = C.INDID
				
				
-------------------------------
-- Index fragmentation stats - tip 2979
-------------------------------		
SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, 'Limited')

SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, 'Sampled')

SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, 'Detailed')


SELECT DB_NAME(DATABASE_ID) AS 'DatabaseName',
       OBJECT_NAME([OBJECT_ID]) AS 'TableName',
       INDEX_ID,
       CAST(INDEX_TYPE_DESC AS VARCHAR(20)) AS INDEX_TYPE_DESC,
       AVG_FRAGMENTATION_IN_PERCENT, page_count, index_type_desc, fragment_count, avg_fragment_size_in_pages
FROM   SYS.DM_DB_INDEX_PHYSICAL_STATS (DB_ID(),NULL,NULL,NULL,NULL )
ORDER BY avg_fragmentation_in_percent desc, page_count desc
				
------------
-- Missing index stats - tip 2979
-------------------------------
SELECT
   @@SERVERNAME AS [ServerName]
   , DB_NAME() AS [DatabaseName]
   , SCHEMA_NAME([sObj].[schema_id]) AS [SchemaName]
   , [sObj].[name] AS [ObjectName]
   , CASE [sObj].[type]
      WHEN 'U' THEN 'Table'
      WHEN 'V' THEN 'View'
      ELSE 'Unknown'
     END AS [ObjectType]
   , [sdmvMID].[equality_columns] AS [EqualityColumns]
   , [sdmvMID].[inequality_columns] AS [InequalityColumns]
   , [sdmvMID].[included_columns] AS [IncludedColumns]
   , [sdmvMIGS].[user_seeks] AS [ExpectedIndexSeeksByUserQueries]
   , [sdmvMIGS].[user_scans] AS [ExpectedIndexScansByUserQueries]
   , [sdmvMIGS].[last_user_seek] AS [ExpectedLastIndexSeekByUserQueries]
   , [sdmvMIGS].[last_user_scan] AS [ExpectedLastIndexScanByUserQueries]
   , [sdmvMIGS].[avg_total_user_cost] AS [ExpectedAvgUserQueriesCostReduction]
   , [sdmvMIGS].[avg_user_impact] AS [ExpectedAvgUserQueriesBenefitPct]
FROM 
   [sys].[dm_db_missing_index_details] AS [sdmvMID]
   LEFT JOIN [sys].[dm_db_missing_index_groups] AS [sdmvMIG]
      ON [sdmvMID].[index_handle] = [sdmvMIG].[index_handle]
   LEFT JOIN [sys].[dm_db_missing_index_group_stats] AS [sdmvMIGS]
      ON [sdmvMIG].[index_group_handle] = [sdmvMIGS].[group_handle]
   INNER JOIN [sys].[objects] AS [sObj]
      ON [sdmvMID].[object_id] = [sObj].[object_id]
WHERE
   [sdmvMID].[database_id] = DB_ID()  -- Look in the Current Database
   AND [sObj].[type] IN ('U','V')     -- Look in Tables & Views
   AND [sObj].[is_ms_shipped] = 0x0   -- Exclude System Generated Objects
An unhandled error has occurred. Reload 🗙