web-dev-qa-db-fra.com

Comment trouver des index inutilisés?

Je travaille sur un entrepôt de données. J'ai des tables avec jusqu'à 200 millions d'enregistrements. Certaines de ces tables ont environ 20+ index (je ne peux pas expliquer pourquoi elles ont été créées en premier lieu). Cela rend le travail de maintenance de ces index trop pénible et a un impact direct sur le travail d'importation DWH en termes de performances et d'exécution.

Comment trouver les index les moins utilisés sur chaque table? (pour s'en débarrasser)

11
Moslem Ben Dhaou

Essayez ce script, il m'a aidé dans le passé:

-- Unused Index Script
-- Original Author: Pinal Dave 
SELECT TOP 25
o.name AS ObjectName
, i.name AS IndexName
, i.index_id AS IndexID
, dm_ius.user_seeks AS UserSeek
, dm_ius.user_scans AS UserScans
, dm_ius.user_lookups AS UserLookups
, dm_ius.user_updates AS UserUpdates
, p.TableRows
, 'DROP INDEX ' + QUOTENAME(i.name)
+ ' ON ' + QUOTENAME(s.name) + '.'
+ QUOTENAME(OBJECT_NAME(dm_ius.OBJECT_ID)) AS 'drop statement'
FROM sys.dm_db_index_usage_stats dm_ius
INNER JOIN sys.indexes i ON i.index_id = dm_ius.index_id 
AND dm_ius.OBJECT_ID = i.OBJECT_ID
INNER JOIN sys.objects o ON dm_ius.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN (SELECT SUM(p.rows) TableRows, p.index_id, p.OBJECT_ID
FROM sys.partitions p GROUP BY p.index_id, p.OBJECT_ID) p
ON p.index_id = dm_ius.index_id AND dm_ius.OBJECT_ID = p.OBJECT_ID
WHERE OBJECTPROPERTY(dm_ius.OBJECT_ID,'IsUserTable') = 1
AND dm_ius.database_id = DB_ID()
AND i.type_desc = 'nonclustered'
AND i.is_primary_key = 0
AND i.is_unique_constraint = 0
ORDER BY (dm_ius.user_seeks + dm_ius.user_scans + dm_ius.user_lookups) ASC

http://blog.sqlauthority.com/2011/01/04/sql-server-2008-unused-index-script-download/

10
Ron5504

J'ai trouvé que le script BlitzIndex gratuit gratuit de Brent Ozar Unlimited (écrit par Kendra Little) est le meilleur moyen d'isoler les index non utilisés (ainsi que les index qui peuvent être ajoutés, les index qui reproduisent le travail d'autres index, etc.)

http://www.brentozar.com/blitzindex/

Il vous indiquera le nombre de fois où un index a été lu depuis la dernière réinitialisation du nombre de statistiques (ou si un index a été créé/recréé).

Il me semble que Brent Ozar a déclaré lors d'une webémission qu'une bonne règle de base n'est pas plus de 10 index pour une table qui est souvent lue, 20 pour les tables qui sont des données statiques/historiques/archivées qui ne changeront pas fréquemment.

Si vous rencontrez toujours des problèmes avec la vitesse d'importation, y a-t-il un moment où la base de données n'est pas activement interrogée (c'est peut-être en dehors des heures de bureau). Il peut être avantageux de supprimer l'index, d'importer les données, puis de réappliquer les index. (Les statistiques seront bien sûr réinitialisées.) La raison en est que les index seront mis à jour au fur et à mesure que chaque enregistrement entre, les pages seront réorganisées et cela prend du temps et des E/S disque. La construction des index après nécessite une seule analyse de la table.

Aucune règle stricte et rapide, vous devrez peut-être expérimenter cela en fonction des types d'index et des données impliquées. Les index doivent être régulièrement revus à mesure que les besoins/requêtes changent.

10
Greg Robson

J'ai ajouté la dernière date et le dernier code utilisé pour passer à la requête de Raj.

SELECT   OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], 
             I.[NAME] AS [INDEX NAME], type_desc,
             coalesce(last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup) as LastUsed,
             USER_SEEKS, 
             USER_SCANS, 
             USER_LOOKUPS, 
             USER_UPDATES ,
             last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup,
             'drop index ['+I.[NAME]+'] on ['+OBJECT_NAME(S.[OBJECT_ID])+'];' as DropStatement
    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 
    order by type_desc,coalesce(last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup) desc
0
mike nelson

Essaye ça:

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 

Raj

0
Raj