Voici une petite procédure stockée qui permet de connaître l’état physique des index (nombre de pages du niveau feuille, fragmentation et taux d’utilisation des pages) en même temps que la façon dont ils sont utilisés (nombres de seeks et de scans, …).
Elle est utilisable pour collecter ces statistiques sur l’ensemble d’une base de données, ou bien sur une table en particulier
Voici le code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | ------------------------------- -- Nicolas SOUQUET - 04/05/2010 ------------------------------- CREATE PROCEDURE ps_get_index_stats @_table_name sysname = NULL AS BEGIN SET NOCOUNT ON -- Si le nom de la table n'exsite pas, -- alors cela revient à passer NULL en object_id à la fonction sys.dm_db_index_physical_stats -- ce qui a pour effet de collecter toutes les statististiques de tous les index de la BD IF ( @_table_name IS NOT NULL AND NOT EXISTS ( SELECT * FROM sys.tables WHERE name = @_table_name ) ) BEGIN RAISERROR('The table %s does not exist', 16, 1, @_table_name) RETURN END SELECT D.name AS database_name , O.name AS table_name , I.name AS index_name , CASE IPS.index_type_desc WHEN 'CLUSTERED INDEX' THEN 'CL' WHEN 'NONCLUSTERED INDEX' THEN 'N-CL' ELSE IPS.index_type_desc END AS index_type , IUS.user_updates , IUS.user_seeks , IUS.user_scans , IUS.last_user_seek , IUS.last_user_scan , IPS.index_depth , IPS.page_count , CAST(IPS.avg_fragmentation_in_percent AS decimal(5, 2)) AS frag , CAST(IPS.avg_page_space_used_in_percent AS decimal(5, 2)) AS page_usage , STATS_DATE(IPS.object_id, IPS.index_id) AS last_update FROM sys.dm_db_index_physical_stats ( DB_ID() -- Base de données , OBJECT_ID(@_table_name) -- Table , NULL -- Index , NULL -- Partition , 'DETAILED' -- Niveau de détail ) IPS LEFT JOIN sys.dm_db_index_usage_stats AS IUS ON IUS.database_id = IPS.database_id AND IUS.object_id = IPS.object_id AND IUS.index_id = IPS.index_id INNER JOIN sys.databases AS D ON D.database_id = IPS.database_id INNER JOIN sys.indexes AS I ON I.object_id = IPS.object_id AND I.index_id = IPS.index_id INNER JOIN sys.objects AS O ON O.object_id = IPS.object_id WHERE IPS.index_level = 0 AND IPS.alloc_unit_type_desc <> 'LOB_DATA' END |
Et deux exemples d’utilisation :
=> EXEC ps_get_index_stats
Collecte les statistiques de tous les index de la base de données
=> EXEC ps_get_index_stats 'maTable'
Collecte les statistiques de tous les index de la table maTable
Vous pouvez bien sûr modifier son code pour pouvoir filtrer par base de données, par index et par partition.
Attention en revanche, car si l’on passe des paramètres incorrects (valeurs négatives ou pas de valeur (NULL)) aux fonctions DB_ID() et OBJECT_ID(), cela a pour effet de collecter toutes les statistiques avec comme granularité la plus élevée.
On peut utiliser ce script pour décider de la reconstruction ou de la réorganisation d’un index …
Bonne indexation
ElSüket