Ceci est une question intéressante. J'ai travaillé sur cette même question au cours de la dernière semaine. Il existe une table système appelée dm_db_index_usage_stats qui contient des statistiques d'utilisation sur les index.
index Jamais apparaissons dans les statistiques d'utilisation Tableau
Cependant, de nombreux indices apparaissent jamais dans ce tableau du tout. La requête affichée par David Andres répertorie tous les index pour ce cas. Je l'ai mis à jour un peu pour ignorer les clés primaires, qui ne devraient probablement pas être supprimées, même si elles ne sont jamais utilisées. J'ai également joint la table dm_db_index_physical_stats pour obtenir d'autres informations, notamment le nombre de pages, la taille de l'index total et le pourcentage de fragmentation. Une remarque intéressante est que les index renvoyés par cette requête ne semblent pas apparaître dans le rapport SQL pour les statistiques d'utilisation de l'index.
DECLARE @dbid INT
SELECT @dbid = DB_ID(DB_NAME())
SELECT Databases.Name AS [Database],
Objects.NAME AS [Table],
Indexes.NAME AS [Index],
Indexes.INDEX_ID,
PhysicalStats.page_count as [Page Count],
CONVERT(decimal(18,2), PhysicalStats.page_count * 8/1024.0) AS [Total Index Size (MB)],
CONVERT(decimal(18,2), PhysicalStats.avg_fragmentation_in_percent) AS [Fragmentation (%)]
FROM SYS.INDEXES Indexes
INNER JOIN SYS.OBJECTS Objects ON Indexes.OBJECT_ID = Objects.OBJECT_ID
LEFT JOIN sys.dm_db_index_physical_stats(@dbid, null, null, null, null) PhysicalStats
on PhysicalStats.object_id = Indexes.object_id and PhysicalStats.index_id = indexes.index_id
INNER JOIN sys.databases Databases
ON Databases.database_id = PhysicalStats.database_id
WHERE OBJECTPROPERTY(Objects.OBJECT_ID,'IsUserTable') = 1
AND Indexes.type = 2 -- Nonclustered indexes
AND Indexes.INDEX_ID NOT IN (
SELECT UsageStats.INDEX_ID
FROM SYS.DM_DB_INDEX_USAGE_STATS UsageStats
WHERE UsageStats.OBJECT_ID = Indexes.OBJECT_ID
AND Indexes.INDEX_ID = UsageStats.INDEX_ID
AND DATABASE_ID = @dbid)
ORDER BY PhysicalStats.page_count DESC,
Objects.NAME,
Indexes.INDEX_ID,
Indexes.NAME ASC
index apparaissent dans les statistiques de __gVirt_NP_NN_NNPS<__ Utilisation table, mais ne sont jamais utilisés
Il existe d'autres indices qui apparaissent dans la table dm_db_index_usage_stats, mais qui ont jamais été utilisés pour cherche utilisateur, scans , ou des recherches. Cette requête identifiera les index qui entrent dans cette catégorie. Incidemment, contrairement aux index renvoyés par l'autre requête, les index renvoyés dans cette requête peuvent être vérifiés sur le rapport SQL par les statistiques d'utilisation de l'index.
J'ai ajouté un nombre minimal de pages qui me permet de me concentrer sur les index inutilisés qui occupent beaucoup de mémoire.
DECLARE @MinimumPageCount int
SET @MinimumPageCount = 500
SELECT Databases.name AS [Database],
Indexes.name AS [Index],
Objects.Name AS [Table],
PhysicalStats.page_count as [Page Count],
CONVERT(decimal(18,2), PhysicalStats.page_count * 8/1024.0) AS [Total Index Size (MB)],
CONVERT(decimal(18,2), PhysicalStats.avg_fragmentation_in_percent) AS [Fragmentation (%)],
ParititionStats.row_count AS [Row Count],
CONVERT(decimal(18,2), (PhysicalStats.page_count * 8.0 * 1024)/ParititionStats.row_count) AS [Index Size/Row (Bytes)]
FROM sys.dm_db_index_usage_stats UsageStats
INNER JOIN sys.indexes Indexes
ON Indexes.index_id = UsageStats.index_id
AND Indexes.object_id = UsageStats.object_id
INNER JOIN sys.objects Objects
ON Objects.object_id = UsageStats.object_id
INNER JOIN SYS.databases Databases
ON Databases.database_id = UsageStats.database_id
INNER JOIN sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS PhysicalStats
ON PhysicalStats.index_id = UsageStats.Index_id
and PhysicalStats.object_id = UsageStats.object_id
INNER JOIN SYS.dm_db_partition_stats ParititionStats
ON ParititionStats.index_id = UsageStats.index_id
and ParititionStats.object_id = UsageStats.object_id
WHERE UsageStats.user_scans = 0
AND UsageStats.user_seeks = 0
AND UsageStats.user_lookups = 0
AND PhysicalStats.page_count > @MinimumPageCount -- ignore indexes with less than 500 pages of memory
AND Indexes.type_desc != 'CLUSTERED' -- Exclude primary keys, which should not be removed
ORDER BY [Page Count] DESC
J'espère que cela aide.
Pensée finale
Bien sûr, une fois que les index sont identifiés comme candidats pour le retrait, une attention particulière doit être employée encore pour vous assurer qu'il est une bonne décision de le faire.
Pour plus d'informations, consultez Identifying Unused Indexes in a SQL Server Database