Business Geek

Aller au contenu | Aller au menu | Aller à la recherche

mercredi 13 août 2008

Indexation - Gérer la fragmentation

Je continue ma série sur les index avant de faire une petite pause pour préparer une traduction d'article sur les clauses WHERE dynamiques d'un collègue MVP suédois.

Dans ce post, je vais m'intéresser à la fragmentation des index. J'espère que le terme fragmentation rappelera à certains le temps où on passait notre samedi après midi à défragmenter nos disques de 40Mo (oui, méga-octets) pour gagner quelques octets et installer Phantasmagoria.

Le principe est le même, l'idée est de "ranger" un index pour gagner un peu de place et surtout qu'il soit plus performant. La fragmentation est un processus "naturel", dû aux modifications des données. La base vit, grandit et donc il faut opérer de la maintenance régulièrement.

On a 2 types de fragmentation :

  • celle qui touche le niveau feuille de l'index et qui correspond à un ordre sur le disque différent de l'ordre logique dans l'index. Le résultat est trop d'accès disque lors de scans sur ce niveau
  • celle qui touche l'arbre de l'index et qui correspond à des pages trop vides ou trop pleines

On peut utiliser 2 approches pour traiter avec la fragmentation :

  • Traiter systématiquement l'ensemble de sa base de données. C'est la méthode que j'utilise pour des petites volumétries et quand on dispose d'une fenêtre de tir pour faire les opérations de maintenance sans gêner personne (par exemple une base qui est utilisée avec des horaires de bureau).
  • Traiter uniquement les index fragmentés et de façon intelligente. C'est la méthode que j'utilise pour des grosses volumétries et des bases en accès 24/7.

Pour le premier cas, on fait juste un plan de maintenance dans lequel on demande une réorganisation ou une reconstruction des index sur toute la base. Sauf cas contraire, je fais un REORGANIZE tous les soirs et un REBUILD le week-end (cela ne reste qu'une stratégie parmi d'autres). Pour les puristes, les instructions T-SQL sont :

ALTER INDEX IX_abcd ON maTable REORGANIZE

ALTER INDEX IX_abcd ON maTable REBUILD

Pour le second cas, il faut déterminer si un index a besoin d'une reconstruction ou d'une réorganisation et connaître la volumétrie (et par conséquent le temps que ça va prendre) pour limiter l'impact sur la production.

On connait la fragmentation d'un index avec la vue système sys.dm_db_index_physical_stats et plus précisément le champ avg_fragmentation_in_percent. Ainsi on peut connaître pour chaque index son niveau de fragmentation :

SELECT DB_NAME(database_id), OBJECT_NAME(object_id), index_id, avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(
   DB_ID('MaBase'),
   OBJECT_ID('MaTable'),
   NULL, NULL, NULL)

Je ne vais pas rentrer ici dans le détail du pourcentage remonté par SQL Server, je vais lui faire confiance pour le calcul (note : SQL Server 2008 est plus précis dans le calcul car il prend en compte plus de cas).
Sur l'action a mener en fonction de la fragmentation, on trouve toutes les stratégies. Selon Microsoft, on réorganise pour une fragmentation < 30% et on reconstruit au-delà. Moi je n'ai pas de seuil arrêté, il m'arrive de faire un REBUILD quand la fragmentation est > 10%.

Voila, ce post est loin d'être exhaustif car je ne parle pas de la fragmentation par niveau de l'index, du paramètre FILL_FACTOR ou de la reconstruction ONLINE qui permet de reconstruire un index avec peu d'impact sur la production (version Enterprise uniquement).

PS : pour connaître le nom de l'index visé (la requête ci-dessus ne remonte que l'id), il va falloir faire une jointure sur sys.indexes.

Mise à Jour : pour illustrer le problème de la fragmentation d'un index, voici 2 images montrant un index "propre" et un index fragmenté.

Index non-fragmenté

Index fragmenté

Et comme il faut rendre à César ce qui lui appatient, voici mes sources : http://technet.microsoft.com/en-us/magazine/cc671165.aspx

mardi 12 août 2008

Indexation - Faites la chasse aux index HEAP

Un premier post qui j'espère me conduira à une série sur l'indexation dans SQL Server. Je traiterai les points un peu dans le désordre mais n'est-ce pas là l'attrait d'un blog ? Je sais que je ne commence pas par les bases mais bon, j'attend vos questions :-).

Un index de type HEAP indique en réalité le fait qu'il n'y ait aucun index sur la table et surtout pas d'index CLUSTERED. C'est à dire que seul le CREATE TABLE a été exécuté, sans aucune option, sans PRIMARY KEY.

Cela signifie que les données sont rangées n'importe comment ou plutôt dans l'ordre de leur création. C'est comme si je prenais un annuaire et que je mélangais les villes et les noms.

La conséquence d'avoir ce type d'indexation dans sa base de données est très souvent d'avoir des performances catastrophiques lors de la selection de données. D'autant plus quand la volumétrie augmente. Ceci vient du fait que l'opération qui est faite sur la table pour récupérer un jeu d'enregistrement est un TABLE SCAN (aussi appelé Full Scan).

Pour en revenir à mon annuaire, c'est comme si je vous demandais de me trouver toutes les personnes qui habitent au 12, rue des saules, quelque soit la ville. Vous seriez obligé de lire (scanner) toutes les pages.

Pour limiter cela, on peut mettre un index clustered ou une PRIMARY KEY (équivalent d'un index unique non null) pour optimiser la recherche.

Pour retrouver toutes les tables concernées :

select OBJECT_NAME(sys.indexes.object_id)
from sys.indexes
  inner join sys.tables on sys.tables.object_id = sys.indexes.object_id
where sys.indexes.[type] = 0 --0 = HEAP

Donc faite un petit check-up de vos bases et vérifier vos tables stockées sur un index HEAP... Et pourquoi pas les mettre sur un index CLUSTERED... mais je reviendrai sur ce point ;-)

 

 

 

 

 

mardi 29 janvier 2008

Vues indexées et optimisation

Les vues indexées sont un excellent vecteur d'optimisation et j'en suis un des ardents défenseurs !! Je les utilise depuis SQL Server 2000 pour optimiser des requêtes un peu complexes ou fréquemment utilisées. Le but de ce post n'est pas de détailler les vues indexées mais de présenter un problème qui m'est arrivé.

Lors d'une formation SQL Server, je présente comme d'habitude l'intérêt des vues indexées et on décide de faire une petite démo avec AdventureWorks. L'idée est d'optimiser la récupération des descriptions de produits. La vue est la suivante : 

Create View [dbo].[vProdDesc]
WITH SCHEMABINDING
as
select p.name, d.description
from production.product p
    inner join Production.ProductModelProductDescriptionCulture dc
        on dc.ProductModelID = p.ProductModelID
        and cultureid = 'fr'
    inner join production.productdescription d
        on d.ProductDescriptionID = dc.ProductDescriptionID

Je pose un index UNIQUE et CLUSTERED sur la vue et pour montrer l'utilisation de l'index j'exécute un simple SELECT sur la vue :

Select * From dbo.vProdDesc

Le plan d'exécution généré montre clairement que l'index n'est pas utilisé. J'utilise donc tous les grigris SQL en ma possession : DBCC FREEPROCCACHE, sp_recompile, table hint, mais rien n'y fait.

Un petit tour dans l'aide pour voir si je n'ai pas zappé quelquechose et je tombe sur une phrase annodine :

Indexed views can be created in any edition of SQL Server 2005. In SQL Server 2005 Enterprise Edition, the query optimizer automatically considers the indexed view. To use an indexed view in all other editions, the NOEXPAND table hint must be used.

Je n'ai pourtant jamais utiliser ce hint pour activer des vues indexées. Et pourtant, en l'ajoutant à ma requête, le plan d'exécution est correct et tire bénéfice de l'index.

Select * From dbo.vProdDesc WITH (NOEXPAND)

Un coup d'oeil sur la version :

Select @@version

Microsoft SQL Server 2005 - 9.00.3054.00 (Intel X86)   Mar 23 2007 16:28:52   Copyright (c) 1988-2005 Microsoft Corporation  Developer Edition on Windows NT 6.0 (Build 6000: )

Conclusion : l'édition Developer est bien bridée par rapport à la version Enterprise. Et l'effet de bord à cela c'est que l'on ne peut pas utiliser de vue indexées dites "techniques" (ie. utilisées implicitement par l'optimiseur de requêtes) car on ne peut pas préciser l'option NOEXPAND si la vue n'est pas utilisée directement.

Ce que je ne comprends pas c'est qu'il me semblait toujours avoir développé sur des Developer Edition or je n'ai jamais rencontré cet effet de bord. Donc je commence à croire que c'était des Enterprise... Ah le luxe, quand tu nous tiens...