Sie sind auf Seite 1von 267

Optimisation des bases de

Rfrence

donnes

Mise en uvre sous Oracle


Laurent Navarro

Rseaux et tlcom Programmation Dveloppement web Scurit Systme dexploitation

Optimisation des bases de donnes


Mise en uvre sous Oracle
Laurent Navarro

Avec la contribution technique dEmmanuel Lecoester

Pearson Education France a apport le plus grand soin la ralisation de ce livre afin de vous fournir une information complte et fiable. Cependant, Pearson Education France nassume de responsabilits, ni pour son utilisation, ni pour les contrefaons de brevets ou atteintes aux droits de tierces personnes qui pourraient rsulter de cette utilisation. Les exemples ou les programmes prsents dans cet ouvrage sont fournis pour illustrer les descriptions thoriques. Ils ne sont en aucun cas destins une utilisation commerciale ou professionnelle. Pearson Education France ne pourra en aucun cas tre tenu pour responsable des prjudices oudommages de quelque nature que ce soit pouvant rsulter de lutilisation de ces exemples ou programmes. Tous les noms de produits ou marques cits dans ce livre sont des marques dposes par leurs propritaires respectifs.
Publi par Pearson Education France 47 bis, rue des Vinaigriers 75010 PARIS Tl. : 01 72 74 90 00 www.pearson.fr Mise en pages : TyPAO ISBN : 978-2-7440-4156-3 Copyright 2010 Pearson Education France Tous droits rservs

Aucune reprsentation ou reproduction, mme partielle, autre que celles prvues larticle L. 122-5 2 et 3 a) du code de la proprit intellectuelle ne peut tre faite sans lautorisation expresse de Pearson Education France ou, le cas chant, sans le respect des modalits prvues larticle L. 122-10 dudit code.

Table des matires


Prface ............................................................................................................................................... propos de lauteur ...................................................................................................................... Introduction ..................................................................................................................................... 1 Introduction aux SGBDR ................................................................................................... 1.1 1.2 Quest-ce quune base de donnes? ....................................................................
IX

XI 1 5 5 6 7 7 10 10 11 12 13 14 15 15 16

1.1.1 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6


1.3 1.4

Systme de gestion des bases de donnes ...................................... Organisation des donnes .................................................................. Le RowID ............................................................................................... Online Redo Log et Archived Redo Log ........................................ Organisation des tables ........................................................................ Row Migration et Row Chaining ...................................................... Le cache mmoire ................................................................................

Modle de stockage des donnes .........................................................................

Intrt des index dans les SGBDR ....................................................................... Analyse du comportement du SGBDR ...............................................................

1.4.1 1.4.2

Excution dune requte SQL............................................................ Optimiseur CBO (Cost Based Optimizer) ......................................
Axe 1 tude et optimisation dumodle de donnes

Modle relationnel ................................................................................................................ 2.1 2.2 Prsentation .............................................................................................................. Les bons rflexes sur le typage des donnes ......................................................

21 21 25 28

2.2.1

Les types sous Oracle ..........................................................................

IV

Optimisation des bases de donnes

2.2.2 2.2.3
3

Les types sous SQL Server ................................................................. Les types sous MySQL........................................................................

30 31 33 33 34 35 36 37 38 38 38 40 42 43

Normalisation, base du modle relationnel ................................................................... 3.1 Normalisation ..........................................................................................................

3.1.1 3.1.2 3.1.3 3.1.4 3.1.5


3.2

Premire forme normale (1NF) ......................................................... Deuxime forme normale (2NF) ....................................................... Troisime forme normale (3NF) ....................................................... Forme normale de Boyce Codd (BCNF) ........................................ Autres formes normales ...................................................................... La dnormalisation pour historisation ............................................. La dnormalisation pour performance et simplification en environnement OLTP ..................................................................... La dnormalisation pour performance en environnement OLAP ....................................................................

Dnormalisation et ses cas de mise en uvre ....................................................

3.2.1 3.2.2 3.2.3


3.3

Notre base de test ....................................................................................................

Axe 2 tude et optimisation desrequtes 4 Mthodes et outils de diagnostic ....................................................................................... 4.1 Approche pour optimiser ....................................................................................... 49 49 50 55 61 64 64 65 66 67 72 73

4.1.1 4.1.2 4.1.3


4.2

Mesurer.................................................................................................... Comprendre le plan dexcution ....................................................... Identifier les requtes qui posent des problmes........................... Compteurs de performance Windows .............................................. SQL Tuning Advisor (Oracle) ........................................................... SQL Access Advisor (Oracle)............................................................ SQL Trace (Oracle)............................................................................... Outils SQL Server................................................................................. Outils MySQL .......................................................................................

Outils complmentaires .........................................................................................

4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6

Table des matires

Techniques doptimisation standard au niveau base de donnes ............................ 5.1 Statistiques sur les donnes ...................................................................................

77 77 78 78 80 85 86 99 100 101 108 111 118 118 122 132 135 146 148 153 153 154 155 156 158 159 160 161 162 163 163 163 164 164

5.1.1 5.1.2 5.1.3


5.2

Ancienne mthode de collecte ........................................................... Nouvelle mthode de collecte............................................................ Slectivit, cardinalit, densit .......................................................... Index B*Tree.......................................................................................... Index sur fonction ................................................................................. Reverse Index......................................................................................... Index bitmap........................................................................................... Bitmap Join Index ................................................................................. Full Text Index ....................................................................................... Paramtres de table ............................................................................... Index Organized Table ........................................................................ Cluster ...................................................................................................... Partitionnement des donnes.............................................................. Les vues matrialises ......................................................................... Reconstruction des index et des tables ............................................

Utilisation des index ...............................................................................................

5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6


5.3

Travail autour des tables ........................................................................................

5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6


6

Techniques doptimisation standard des requtes ....................................................... 6.1 Rcriture des requtes ..........................................................................................

6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8


6.2

Transformation de requtes ................................................................ IN versus jointure.................................................................................. Sous-requtes versus anti-jointures .................................................. Exists versus Count .............................................................................. Exists versus IN ..................................................................................... Clause Exists * versus constante ....................................................... Expressions sous requtes .................................................................. Agrgats: Having versus Where ....................................................... Mlange des types ................................................................................ Fonctions et expressions sur index ................................................... Impact de loprateur <> sur les index ............................................ Rutilisation de vue ..............................................................................

Bonnes et mauvaises pratiques .............................................................................

6.2.1 6.2.2 6.2.3 6.2.4

VI

Optimisation des bases de donnes

6.2.5 6.2.6 6.2.7 6.2.8 6.2.9 6.2.10 6.2.11 6.2.12 6.2.13 6.2.14 6.2.15 6.2.16 6.2.17
7

Utilisation de tables temporaires....................................................... Utilisation abusive de SELECT * ...................................................... Suppression des tris inutiles ............................................................... Utilisation raisonne des oprations ensemblistes ....................... Union versus Union ALL..................................................................... Count(*) versus count(colonne) ........................................................ Rduction du nombre de parcours des donnes ............................ LMD et cls trangres........................................................................ Suppression temporaire des index et des CIR ............................... Truncate versus Delete ........................................................................ Impacts des verrous et des transactions........................................... Optimisation du COMMIT ................................................................. DBLink et vues......................................................................................

165 165 166 166 169 170 171 172 173 173 173 175 176 177 177 179 179 180 181 182 183 183 185 186 186 188 189 191 192 194 195 196 198

Techniques doptimisation des requtes avances ....................................................... 7.1 Utilisation des hints sous Oracle ..........................................................................

7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.1.6


7.2 7.3

Syntaxe gnrale ................................................................................... Les hints Optimizer Goal .................................................................... Les hints Access Path ........................................................................... Les hints Query Transformation ....................................................... Les hints de jointure ............................................................................. Autres hints............................................................................................. Les hints de paralllisme..................................................................... Les Grouping Sets................................................................................. Rollup Group By.................................................................................... Cube Group By ...................................................................................... Utilisation de WITH ............................................................................. Les fonctions de classement (ranking) ............................................ Autres fonctions analytiques .............................................................. Linstruction MERGE .......................................................................... Optimisation des updates multitables .............................................. Insertion en mode Direct Path ...........................................................

Excution parallle .................................................................................................

7.2.1 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.3.7 7.3.8 7.3.9

Utilisation du SQL avanc.....................................................................................

Table des matires

VII

7.4

PL/SQL .....................................................................................................................

198 198 200 203 208 209 210 212 212

7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.4.6 7.4.7 7.4.8

Impact des triggers ............................................................................... Optimisation des curseurs (BULK COLLECT) ............................. Optimisation du LMD (FORALL) .................................................... SQL dynamique et BULK ................................................................... Traitement des exceptions avec FORALL....................................... Utilisation de cache de donnes ........................................................ Utilisation du profiling ........................................................................ Compilation du code PL/SQL ...........................................................

Axe 3 Autres pistes doptimisation 8 Optimisation applicative (hors SQL) ............................................................................. 8.1 8.2 8.3 8.4 8.5 8.6 9 Impact du rseau sur le modle client/serveur ................................................... Regroupement de certaines requtes ................................................................... Utilisation du binding............................................................................................. Utilisation de cache local lapplication ............................................................ Utilisation du SQL procdural .............................................................................. Gare aux excs de modularit ............................................................................... 217 217 217 219 221 221 221 223 223 223 224 224 224 225 225 226 227

Optimisation de linfrastructure ...................................................................................... 9.1 Optimisation de lexcution du SGBDR .............................................................

9.1.1 9.1.2
9.2

Ajustement de la mmoire utilisable................................................ Rpartition des fichiers ........................................................................ Le CPU .................................................................................................... La mmoire vive (RAM)..................................................................... Le sous-systme disque ....................................................................... Le rseau .................................................................................................

Optimisation matrielle..........................................................................................

9.2.1 9.2.2 9.2.3 9.2.4

Conclusion ........................................................................................................................................

VIII

Optimisation des bases de donnes

Annexes A Gestion interne des enregistrements................................................................................ A.1 A.2 B Le RowID ................................................................................................................. Row Migration et Row Chaining ......................................................................... 231 231 232 235 235 236 240 241 245 249 251

Statistiques sur les donnes plus en dtail...................................................................... B.1 B.2 B.3 B.4 Statistiques selon lancienne mthode de collecte ............................................ Statistiques selon la nouvelle mthode de collecte ........................................... Histogrammes .......................................................................................................... Facteur de foisonnement (Clustering Factor) ....................................................

C D

Scripts de cration des tables de test bigemp et bigdept.............................................. Glossaire ..................................................................................................................................

Index ...................................................................................................................................................

Prface
Loptimisation des applications est un sujet bien vaste, souvent objet des dbats d'experts et gnrateur de quiproquos notamment sur les causes gnrant les effets constats (lenteur daffichage, fort trafic rseau, saturation du serveur de donnes). Loptimisation se prsente sous de multiples facettes:

Tantt, elle est purement applicative et touche la mthode de programmation. Tantt, les drives proviennent dun manque au niveau de la modlisation des donnes, plus gnralement dun problme d'index ou de paramtrage du serveur de donnes. Parfois mme, loptimisation est tout simplement lie une limite de larchitecture physique du systme.

Dans chacun de ces trois cas de figure majeurs, il est important de mesurer ce manque doptimisation et de choisir les mtriques les plus discriminantes afin de pouvoir mesurer les bnfices exacts de loptimisation apporte. Dans cet ouvrage, Laurent Navarro apporte un lot de rponses concrtes et dtailles au dveloppeur dapplication, dans une vision rsolument cible sur laccs aux donnes. Jinsiste bien sur ce point: ce livre nest pas un catalogue des techniques doptimisation propres chaque serveur de donnes destin aux administrateurs ou autres experts mais bien un premier pas vers une sensibilisation des dveloppeurs de tous bords aux contacts avec un serveur de donnes. Ce livre parcourt les principales techniques doptimisation disponibles pour le dveloppeur dapplication: modle de donnes, techniques standard daccs aux donnes jusqu des techniques trs avances permettant dexploiter au mieux les possibilits offertes par les principaux diteurs de bases de donnes du march. Emmanuel Lecoester Responsable des rubriques SGBD & WinDev de developpez.com

propos de lauteur
Adolescent, je mamusais avec des bases de donnes DBase II & III, puis jai dbut ma carrire dans l'industrie avec des bases en fichiers partags Paradox. La nature des applications a volu, et en 1994 jai commenc travailler sur des bases Oracle (Version 7). lpoque, cela ncessitait un serveur Unix et un DBA bard de certifications. Au fil du temps, les SGBDR client/serveur se sont dmocratises. Des alternatives au leader sont apparues, contribuant pour une grande part cette dmocratisation. Cest ainsi quen 2000 jai fait la connaissance de MySQL (3.2 lpoque) pour ma premire application web dveloppe en PHP. Puis jai eu loccasion dutiliser dautre bases, telles que SQL Server de Microsoft, Firebird la version open-source dInterbase ou encore PostgreSQL, autre alternative open-source qui ne rencontre malheureusement pas le succs quelle mriterait. Paralllement, les clients aussi se sont diversifis, et je constatais que le primtre dutilisation des bases de donnes stendait. Au dbut rserv linformatique de gestion, les bases de donnes sont petit petit apparues dans les secteurs de linformatique industrielle et de linformatique mobile. Ces secteurs ntant pas forcment coutumiers de ces technologies, ils ont fait appel des gens comme moi pour les conseiller dans leur volution. Aimant varier les plaisirs, outre les bases de donnes, je dveloppe en C/C++, parfois en environnement contraint du point de vue des performances. Cest probablement de l que me vient cette curiosit qui me pousse comprendre comment fonctionnent les choses et qui a pour suite naturelle loptimisation. Ajoutez cela le plaisir de partager ses connaissances et vous comprendrez comment est n ce livre, qui jespre vous aidera dans votre travail. Laurent Navarro, dveloppeur dapplications, est bas Toulouse et travaille depuis quinze ans avec des bases de donnes Oracle mais aussi quelques autres (SQL Server, MySQL,etc.). Il anime des formations SQL, PL/SQL, Pro*C et Tuning SQL depuis une dizaine dannes.

Introduction
Pourquoi ce livre, qui s'adresse-t-il?
Loptimisation de bases de donnes est un problme la fois simple et compliqu. Jinterviens souvent auprs de structures qui nont aucune notion doptimisation et, dans ces cas-l, les choses sont plutt simples car lapplication de principes de base doptimisation amliore rapidement la situation. En revanche, lorsque ces principes de base ont dj t appliqus, la tche peut tre plus ardue Lobjectif de cet ouvrage est de fournir les bases de loptimisation. Il explique ce qui se passe dans la base de donnes afin que vous puissiez comprendre ce qui se passe sous le capot de votre SGBDR et, ainsi, vous permettre de choisir des solutions doptimisation en ayant conscience des impacts de vos choix. Il existe dj des livres couvrant ce domaine, mais la plupart sont en anglais et sadressent des DBA (administrateurs de base de donnes). Ces ouvrages sont soit tellement pointus quun non-expert peut sy noyer, soit tellement lgers quon ne comprend pas forcment pourquoi les choses sont censes samliorer. Cela rend dlicate la transposition votre environnement. Jespre avoir trouv un juste milieu avec cet ouvrage. Pour moi, il est primordial daborder le problme de loptimisation ds la conception dun logiciel. Il est donc ncessaire que les dveloppeurs sapproprient ces comptences plutt que de demander aux DBA de trouver des solutions aprs la mise en production. Ce livre sadresse donc en premier lieu aux quipes de dveloppement dveloppeurs, chefs de projet, architectes mais aussi, bien sr, aux DBA qui seront toujours les interlocuteurs naturels des quipes de dveloppement ds quune base de donnes sera utilise.

Optimisation des bases de donnes

Quels sont les prrequis?


Pour lire cet ouvrage, il vous suffit de savoir ce quest une base de donnes relationnelle. Une connaissance du SQL sera un plus.

Quel est le primtre de ce livre?


Ce livre couvre les cas les plus frquents, cest--dire des applications ayant au plus quelques gigaoctets de donnes sur des serveurs classiques. Il ne couvre donc pas des sujets comme lutilisation de GRID, de RAC ou des bases OLAP, mme si de nombreux thmes abords ici sont prsents dans ce type dapplication aussi. Cet ouvrage se focalise sur loptimisation autour du dveloppement. Les optimisations au niveau de linfrastructure de la base de donnes ne seront que trs peu abordes. Dautres livres plus orients sur lexploitation traitent dj ce sujet bien mieux que je ne saurais le faire.

Organisation du livre
Cet ouvrage sarticule autour de neuf chapitres, regroups dans trois parties:

Le Chapitre 1 est une introduction visant prsenter brivement quelques mcanismes internes des SGBDR qui seront ncessaires la comprhension des chapitres suivants.

La premire partie concerne le premier axe doptimisation : celle du modle de donnes.

Le Chapitre2 rappelle ce quest le modle relationnel et traite les problmatiques lies au typage des donnes. Le Chapitre3 traite de lintrt de la normalisation des bases de donnes et de lutilit que peut prsenter la dnormalisation applique bon escient. Le Chapitre4 prsente les mthodes et loutillage. Il traite des diffrents outils votre disposition pour analyser les situations et explique comment comprendre les rsultats.

La deuxime partie concerne le deuxime axe doptimisation: celle des requtes.

Introduction

Le Chapitre 5 dcrit lensemble des objets doptimisation et le cadre de leur utilisation. Il dcrit les diffrents types dindex et dorganisation des tables ainsi que leurs cas dusage. Le Chapitre6 prsente les impacts des variantes dcriture et dcrit quelques bonnes et mauvaises pratiques. Le Chapitre7 introduit les hints quil faut utiliser avec parcimonie, un ensemble de techniques SQL avances ainsi que des optimisations du PL/SQL. Le Chapitre8 traite des optimisations applicatives autres que loptimisation des requtes elles-mmes. Le Chapitre 9 aborde brivement quelques optimisations envisageables au niveau de linfrastructure.

La troisime partie contient dautres axes doptimisations.

Ressources en ligne
Afin dillustrer les concepts prsents tout au long de ce livre, nous allons les appliquer une base de test. Cette base (structure et donnes) est disponible pour les SGBDR Oracle, SQL Server et MySQL sur le site de lauteur, ladresse http://www.altidev.com/livres.php.

Remerciements
Merci ma femme Bndicte et mon fils Thomas pour leur soutien et leur patience durant lcriture de ce livre. Merci ma mre Ginette pour ses relectures. Merci mes relecteurs, Emmanuel et Nicole. Merci mon diteur, Pearson France, et particulirement Patricia pour mavoir fait confiance et Amandine pour ses prcieux conseils. Merci lquipe dIris Technologies pour mavoir donn lide de ce livre en me permettant danimer des formations sur ce sujet.

1
Introduction aux SGBDR
Pour optimiser une base Oracle, il est important davoir une ide de la manire dont elle fonctionne. La connaissance des lments sous-jacents son fonctionnement permet de mieux comprendre ses comportements. Cest pourquoi nous commencerons, ce chapitre, par vous prsenter ou vous rappeler brivement ce quest un SGBDR et quelques-uns des lments qui le composent. Ces notions vous seront utiles tout au long du livre. Le but ici nest pas de faire de vous un spcialiste du fonctionnement interne dOracle, mais de vous donner quelques explications sur des concepts que nous rfrencerons ultrieurement. Si vous tes DBA, vous pouvez vous rendre directement au Chapitre2.

1.1

Qu'est-ce qu'une base de donnes?

Une base de donnes est un ensemble dinformations structures. Elle peut tre de nature:

hirarchique; relationnelle; objet; documentaire;

Actuellement, le march est principalement compos de bases de donnes relationnelles avec, parfois, une extension objet. Cet ouvrage traite exclusivement de ce type de bases.

Optimisation des bases de donnes

Dans les bases de donnes relationnelles, les donnes sont organises dans des tables deux dimensions, conformment au modle relationnel que nous tudierons au Chapitre 2.
1.1.1 Systme de gestion des bases de donnes

Un SGBDR (systme de gestion de base de donnes relationnelle) est un systme (logiciel) qui permet de grer une base de donnes relationnelle. Les SGBDR peuvent tre soit de type client/serveur (Oracle, SQL Server, MySQL, PostgreSQL, etc.), soit de type fichiers partags (Access, SQL Server CE, Paradox, DBase, etc.). Dans le milieu professionnel, on retrouve principalement des SGBDR client/serveur mme si les solutions en fichiers partags ont eu leur heure de gloire et sont encore utilises dans certaines applications. Lapparition de SGBDR client/serveur gratuits a fortement contribu populariser ce modle ces dernires annes. Le modle client/serveur ncessite gnralement la prsence dun serveur, qui traite les requtes transmises par le client et lui retourne le rsultat. Le principal intrt dun SGBDR est quil va fournir les services suivants (tous les SGBDR ne proposent pas tous ces services):

implmentation du langage d'interrogation des donnes SQL (Structured Query Language); gestion des structures des donnes et de leur modification; gestion de lintgrit des donnes; gestion des transactions; gestion de la scurit, contrle daccs; abstraction de la plateforme matrielle et du systme dexploitation sous-jacent; du point de vue logique, abstraction de lorganisation du stockage sous-jacent; tolrance aux pannes et administration du systme; rpartition de la charge.

Chapitre 1

Introduction aux SGBDR

1.2
1.2.1

Modle de stockage des donnes


Organisation des donnes

Les tables sont les objets logiques de base du modle relationnel. Or, un systme dexploitation ne connat que la notion de fichiers. Le SGBDR permet de faire le lien entre la reprsentation logique et le stockage physique dans les fichiers. Nous allons voir comment en tudiant le SGBDR Oracle. Les objets logiques (tables, index, etc.) sont stocks dans des espaces logiques appels "tablespaces". Une base de donnes est constitue de plusieurs tablespaces, lesquels sont composs dun ou de plusieurs fichiers appels "datafiles". Ces fichiers peuvent se trouver sur des disques diffrents.
tablespace TBS_COMPTA d:\OracleData\ DataFileCompta1.Ora d:\OracleData\ DataFileCompta2.Ora Tablespace Espace disque logique

Table Index Index Index Index Index

Table Index Index Index

Index Index Table

data les : Fichiers de donnes

Objets stocks dans le tablespace et repartis sur les data les

Figure1.1 Organisation des objets dans un tablespace compos de deux datafiles.

Les objets sont attachs un seul tablespace mais ils peuvent, par contre, tre rpartis sur plusieurs datafiles (voir Figure 1.1). Il ny a aucun moyen dinfluer sur la localisation des objets au niveau des datafiles, il est seulement possible de dfinir le tablespace associ un objet. (Les objets partitionns peuvent, eux, tre attachs plusieurs tablespaces. Nous les tudierons au Chapitre5, section5.3.4, "Partitionnement des donnes".) Les datafiles, et donc les tablespaces, sont constitus de blocs de donnes (data block), dont la taille est configure la cration du tablespace. Ce paramtre varie gnralement entre 2Ko et 16Ko et, par dfaut, est de 4 ou 8Ko suivant la plateforme

Optimisation des bases de donnes

(au long de louvrage, nous retiendrons une taille de 8Ko qui est une valeur assez communment utilise). Chaque objet ou constituant dobjet ayant besoin de stockage sappelle un "segment". Par exemple, pour une table classique, il y a un segment pour la table ellemme, un segment pour chacun de ses index et un segment pour chacun de ses champs LOB (voir Chapitre 2, section 2.2.1, "Les types sous Oracle"). Quand un segment a besoin despace de stockage, il alloue un extent, cest--dire un ensemble de blocs de donnes contigus. Un segment est donc compos dun ensemble dextents qui nont pas forcment tous la mme taille. (Les clauses INITIAL et NEXT spcifies dans linstruction de cration de lobjet associ au segment permettent dinfluer sur ces paramtres.) La Figure1.2 prsente la dcomposition hirarchique dun segment en blocs de donnes. Il est noter que, si un segment na plus besoin de lespace quil a prcdemment allou, il ne le libre pas ncessairement.
Figure1.2 Dcomposition d'un segment en extents puis en blocs.
8K o Segment 256 Ko

8K

8K

8 Ko 8 Ko 8 Ko 8 Ko 8 Ko 8 Ko 8 Ko 8 Ko

8 K Extent Initial o 128 Ko 8K o 8K 8K 8K 8 Ko 8 Ko 8 Ko 8 Ko o o o 8 Ko 8 Ko

8 K Extent o 64 Ko 8K o 8K 8K 8K 8 Ko 8 Ko o o o 8 Ko 8 Ko

8 K Extent o 64 Ko 8K o 8K 8K 8K 8 Ko 8 Ko o o o 8 Ko 8 Ko

Blocs de donnes (data block)

MS SQL Server
Sous SQL Server, la logique est relativement proche, sauf qu'un niveau supplmentaire est intgr, le niveau base de donnes (database). la diffrence d'Oracle, une instance SQL Server contient plusieurs bases de donnes, qui ont chacune leurs espaces logiques nomms data file group (quivalents des tablespaces) eux-mmes composs de data file.

Chapitre 1

Introduction aux SGBDR

MySQL
Sous MySQL, l'organisation du stockage est dlgue au moteur de stockage. Plusieurs moteurs sont supports, MyISAM et InnoDB le plus frquemment. Le moteur MyISAM attribue plusieurs fichiers chaque table. Un fichier .frm pour dcrire la structure de la table. Ce fichier est gr par MySQL et non pas par le moteur de stockage. Un fichier .myd qui contient les donnes. Un fichier .myi qui contient les index. Le moteur InnoDB implmente le concept de tablespace qui contient tous les lments de la base de donnes (tables, index, etc.). Les fichiers .frm grs par MySQL sont prsents en plus du tablespace.

Les blocs de donnes contiennent les enregistrements (lignes ou row) et des structures de contrle. La Figure 1.3 montre un schma complet de lorganisation du stockage des donnes.
Figure1.3 Schma illustrant le stockage des donnes dans une base Oracle.
Data le Tablespace Segments

Table

Extent Bloc de donnes Bloc de donnes Bloc de donnes Bloc de donnes Bloc de donnes Bloc de donnes Segment (Table) Initial-Extent Next-Extent Next-Extent Next-Extent

Bloc de donnes Entte de bloc Espace libre

Enregistrement

Enregistrement dcompos Taille Taille Taille En-tte Donne Donne Donne Donne Donne Donne

10

Optimisation des bases de donnes

1.2.2

Le RowID

Le RowID (identifiant de ligne) est une information permettant dadresser directement un enregistrement, sans avoir parcourir aucune liste. Cest une sorte de pointeur. Il est compos de:

lidentifiant de lobjet; lidentifiant du datafile; lidentifiant du bloc dans le datafile; lidentifiant de la ligne dans le bloc.

Cette information sera rarement manipule directement par vos applications. Elle est surtout destine un usage interne au SGBDR. Cependant, dans certains cas, il peut tre intressant dy recourir depuis une application, par exemple pour dsigner un enregistrement nayant pas de cl primaire ou pour adresser plus rapidement un enregistrement pour lequel vous avez rcupr le RowID. Le RowID dun enregistrement sobtient en interrogeant la pseudo-colonne rowid.
SQL> select nocmd, noclient, datecommande, rowid from cmd; NOCMD NOCLIENT DATECOMMANDE ROWID ---------- ---------- ------------ -----------------14524 106141 16/04/2004 AAARnUAAGAAASIfAAG 14525 131869 16/04/2004 AAARnUAAGAAASIfAAH 14526 83068 16/04/2004 AAARnUAAGAAASIfAAI 14527 120877 16/04/2004 AAARnUAAGAAASIfAAJ 14528 34288 16/04/2004 AAARnUAAGAAASIfAAK 14529 103897 16/04/2004 AAARnUAAGAAASIfAAL 6 rows selected

Voir lAnnexeA, sectionA.1, pour plus dinformations sur les RowID.


1.2.3 Online Redo Log et Archived Redo Log

Les fichiers Online Redo Log sont des fichiers binaires qui contiennent toutes les modifications appliques aux datafiles rcemment. Ils permettent notamment de rparer les datafiles en cas darrt brutal de la base. Les fichiers Archived Redo Log sont des fichiers Redo Log archivs. Ils sont crs uniquement si le mode archivelog est actif. Ils permettent de rparer les datafiles, de complter une restauration, de maintenir une base de secours en attente (stand by database) et sont aussi ncessaires pour certaines fonctions Oracle Warehouse.

Chapitre 1

Introduction aux SGBDR

11

Leur gestion a un cot en termes despace disque utilis, donc si vous nen avez pas besoin, dsactivez cette fonction.
MS SQL Server
Les fichiers LDF, qui sont les journaux de transactions, jouent un rle analogue aux Online Redo Log.

MySQL
Le moteur InnoDB intgre un mcanisme analogue aux Online Redo Log. Le moteur MyISAM n'a pas d'quivalent.

1.2.4

Organisation des tables

Les donnes sont organises dans des tables deux dimensions: les colonnes, ou champs, qui ne sont pas supposes voluer diffremment du modle de donnes, et les lignes, enregistrements qui varient au fil du temps quand des donnes sont ajoutes ou modifies. Par dfaut, dans de nombreux SGBDR, la structure de stockage adopte est une structure dite de "tas" (heap). Ce type de structure stocke les enregistrements en vrac, sans ordre particulier, dans une zone de donnes. Quand un enregistrement est dtruit, il libre de lespace quun autre enregistrement pourra ventuellement rutiliser. Sous Oracle, en mode MSSM (Manual Segment Space Management), les blocs contenant de lespace libre, cest--dire dont le pourcentage despace libre est suprieur au paramtre PCTFREE de la table, sont lists dans une zone de la table nomme FREELIST. Les blocs dans lesquels de lespace a t libr la suite de suppressions denregistrements et dont le pourcentage despace utilis repasse en dessous de la valeur du paramtre PCTUSED sont, eux aussi, rpertoris dans la FREELIST. Lorganisation des tables sous forme dindex est assez commune, les enregistrements sont stocks dans lordre de la cl primaire. On dit alors que la table est organise en index (IOT, Index Organized Table). Nous tudierons ce type de table au Chapitre5, section5.3.2, "Index Organized Table".

12

Optimisation des bases de donnes

MS SQL Server
Les tables sans index clustered sont organises en tas, celles ayant un index clustered ont une organisation de type IOT.

MySQL
Sous MySQL, les tables utilisant le moteur MyISAM sont organises en tas, celles utilisant le moteur InnoDB ont une organisation de type IOT.

1.2.5

Row Migration et Row Chaining

La migration denregistrement (Row Migration) est le mcanisme qui dplace un enregistrement qui ne tient plus dans son bloc, aprs une mise jour de ses donnes ayant entran un accroissement de sa taille. Lors de la migration, le SGBDR insre un pointeur lemplacement initial de lenregistrement qui dsigne le nouvel emplacement que le SGBDR alloue pour y placer les donnes. Ainsi, on pourra toujours accder lenregistrement en utilisant le RowID initial qui reste valide. Cependant, il faut noter que lutilisation de ce pointeur sera source dE/S (entres/ sorties) supplmentaires. En effet, laccs un enregistrement au moyen de son RowID se fait habituellement en une lecture de bloc, alors que celui un enregistrement ayant migr ncessite de lire deux blocs (celui qui est point par le RowID plus celui qui est dsign par le pointeur). Afin de limiter lapparition de ce phnomne, Oracle ninsre des lignes dans un bloc que si un certain pourcentage despace libre demeure lissue de cette opration (paramtre PCTFREE de la table; par dfaut, il vaut 10%). Le chanage denregistrement (Row Chaining) est le mcanisme qui gre le fait quun enregistrement ne peut pas tenir dans un unique bloc de donnes (8Ko par dfaut) car sa taille est suprieure. Le processus va scinder les donnes et les rpartir dans plusieurs blocs en plaant dans chaque bloc un pointeur vers les donnes situes dans le bloc suivant. Comme lors de la migration denregistrement, ce mcanisme va causer des E/S supplmentaires. Voir lAnnexeA, sectionA.2, pour plus dinformations sur ces mcanismes.

Chapitre 1

Introduction aux SGBDR

13

1.2.6

Le cache mmoire

Les accs disque sont trs lents compars aux accs en mmoire vive (RAM). Approximativement et en simplifiant : un disque dur a un temps daccs qui se compte en millisecondes, alors que celui de la mmoire se compte en nanosecondes. La mmoire vive est donc un million de fois plus rapide que les disques durs. Par ailleurs, la quantit de mmoire vive sur les serveurs tant de plus en plus importante, une optimisation assez vidente consiste implmenter un systme de cache mmoire dans les SGBDR. Le but du cache mmoire est de conserver en mmoire une copie des informations les plus utilises afin de rduire les accs au disque dur. Sous Oracle, ces caches mmoire se trouvent dans SGA (System Global Area), une zone mmoire principale, qui englobe diverses zones, parmi lesquelles:

Database Buffer Cache. Contient les blocs manipuls le plus rcemment. Shared Pool. Contient les requtes rcentes ainsi que le plan dexcution qui leur est associ. Cette zone contient aussi un cache du dictionnaire des donnes.

Le buffer cache contient une copie mmoire des blocs les plus manipuls afin de rduire le nombre daccs disque. Cela aura pour effet damliorer notablement les performances. Dans de nombreux cas, la quantit de mmoire disponible pour le buffer cache sera plus faible que celle des donnes manipules. De fait, il faudra choisir quelles sont les donnes conserver dans le cache et quelles sont celles qui doivent cder leur place de nouvelles donnes. Ce choix sera fait par un algorithme de type MRU (Most Recently Used) qui privilgiera le maintien en mmoire des blocs les plus utiliss rcemment. Afin dviter que le parcours dune grosse table entrane un renouvellement complet du cache, laccs ce type de tables est pondr dfavorablement au profit des petites tables, pondres, elles, positivement. Ces dernires resteront plus longtemps dans le cache, alors que, gnralement, les grosses tables ny seront pas charges entirement.
MS SQL Server
Sous SQL Server, on retrouve un mcanisme tout fait similaire.

14

Optimisation des bases de donnes

MySQL
Sous MySQL, les choses sont un peu diffrentes. On retrouve bien un mcanisme de cache, mais d'une nature diffrente. Le cache de requte permet de garder en cache le rsultat des requtes prcdemment excutes. Le cache mmoire correspondant au buffer cache d'Oracle est, lui, de la responsabilit du moteur de stockage: Le moteur MyISAM n'en a pas. Il part du principe que le systme d'exploitation en possde un et qu'il sera tout aussi efficace d'utiliser celui-l. Cette solution est un peu moins intressante mais elle a l'avantage de simplifier le moteur de stockage. Le moteur InnoDB intgre, lui, un cache mmoire similaire, sur le principe au buffer cache d'Oracle.

1.3

Intrt des index dans les SGBDR

Nous avons vu prcdemment que, dans une table organise en tas, les donnes nont pas dordre particulier. Lorsque le SGBDR cherche une information suivant un critre particulier (on parle de cl de recherche), il na pas dautre choix que de parcourir lensemble des enregistrements pour trouver ceux qui rpondent au critre demand. Vous imaginez aisment que, lorsquil y a beaucoup denregistrements, cette mthode nest pas trs intressante. Cest pour rpondre plus efficacement ce genre de besoin que la notion dindex a t introduite dans les SGBDR. Un index de base de donnes ressemble un peu lindex de ce livre. Il contient une liste ordonne de mots et une rfrence vers la page qui les contient. De plus, lindex est bien plus petit que le livre. Si nous retranscrivons cela en termes de base de donnes, un index contient la cl de recherche et une rfrence vers lenregistrement. Son principal avantage est quil est ordonn. Cela permet dy appliquer des techniques de recherche par dichotomie, beaucoup plus efficaces que les recherches linaires ds que le nombre denregistrements slve. Les index sont intressants avec les tables organises en tas. Cependant, le besoin est le mme avec les tables organises suivant des index (IOT) qui sont dj tries. En effet, si lordre de la table nest pas celui de la cl de recherche, le problme reste entier. Par exemple, si vous grez une liste de personnes trie par numro de Scurit sociale, lorsque vous faites une recherche sur le nom, vous ntes pas plus avanc que la liste soit trie par numro de Scurit sociale ou pas trie du tout.

Chapitre 1

Introduction aux SGBDR

15

Lintrt des index est donc indpendant du type dorganisation de table. Nous tudierons en dtail au Chapitre5, section5.2.1, "Index B*Tree", les index B*Tree, les plus communs. Par la suite, nous aborderons les principaux types dindex disponibles.

1.4
1.4.1

Analyse du comportement du SGBDR


Excution d'une requte SQL

Toute requte SQL envoye au SGBDR suit le mme parcours afin dtre excute. Nous allons tudier ici ce cheminement afin de comprendre comment le SGBDR passe dune requte SQL un ensemble de donnes rsultat. Il faut bien avoir en tte que le SQL, contrairement la plupart des langages informatiques, ne dcrit pas la faon de dterminer le rsultat mais quil permet dexprimer un rsultat attendu. Ainsi, il nexplique pas comment manipuler les tables, mais les liens quil y a entre elles et les prdicats appliquer sur les donnes. Le SGBDR doit trouver le meilleur moyen de rpondre une requte SQL.
tape 1: Parsing et traduction en langage interne

Cette tape consiste interprter le texte de la requte (parsing) et effectuer des contrles syntaxiques. Le SGBDR vrifie si la requte respecte la grammaire dune requte SQL et si les mots cls sont bien placs. Cette tape inclut aussi les contrles smantiques, cest--dire que le SGBDR vrifie si la requte manipule bien des tables et des colonnes qui existent et si lutilisateur possde les droits permettant de faire ce qui est demand dans la requte.
tape 2: tablissement d'un plan d'excution

Le plan dexcution est la faon dont le SGBDR parcourt les diffrents ensembles de donnes afin de rpondre la requte. Nous tudierons au Chapitre 4, section4.1.2, "Comprendre le plan dexcution", les lments primaires constituant un plan dexcution. Lors de cette tape, le SGBDR tablit plusieurs plans dexcution possibles. En effet, tout comme il y a plusieurs algorithmes possibles pour crire un programme, il y a plusieurs plans dexcution possibles pour rpondre une requte.

16

Optimisation des bases de donnes

Ensuite, loptimiseur (voir section 1.4.2) choisi le plan dexcution quil estime tre le meilleur pour excuter la requte, parmi les diffrents plans dexcution possibles.
tape 3: Excution de la requte

Cette tape consiste excuter le plan dexcution dfini ltape prcdente, cest-dire aller chercher les informations dans les tables en passant par les chemins dfinis par le plan dexcution et en extraire le rsultat demand.
INFO La technique du binding que nous tudierons au Chapitre8, section8.3, "Utilisation du binding" permet, lorsqu'une mme requte est excute plusieurs fois avec des paramtres diffrents, de n'excuter qu'une seule fois les tapes1 et2 et ainsi de passer directement l'tape3 lors des excutions suivantes.

1.4.2

Optimiseur CBO (Cost Based Optimizer)

Le rle de loptimiseur est de trouver le plan dexcution le plus performant pour excuter une requte. Oracle est depuis la version7 (dbut des annes 1990) pourvu de deux optimiseurs de requtes:

celui qui est bas sur des rgles (RBO, Rule Based Optimizer, introduit en V6); celui qui est bas sur les cots (CBO, Cost Based Optimizer, introduit en V7).

Sur les versions rcentes dOracle, loptimiseur bas sur les rgles nexiste plus vraiment. Les mots cls permettant la manipulation du RBO sont seulement prsents des fins de rtrocompatibilit (depuis la version10g, le RBO nest plus support). Oracle recommande, depuis plusieurs versions, de ne plus utiliser le RBO et concentre tous ses efforts sur le CBO, cest donc celui-l que nous allons tudier.
MS SQL Server et MySQL
SQL Server et MySQL tant eux aussi munis d'un optimiseur de type CBO, les grands principes tudis ici seront communs.

Le CBO est un optimiseur qui est bas sur lestimation des cots dexcution des oprations des plans dexcution. Pour une requte donne, le SGBDR tablit plusieurs plans dexcution possibles, et le CBO estime pour chacun deux le cot dexcution et choisit le moins lev.

Chapitre 1

Introduction aux SGBDR

17

Comment estimer le cot dun plan dexcution ? Le SGBDR value le cot en ressources utilises pour excuter ce plan. Ces ressources sont:

le temps CPU; le nombre dE/S (entres/sorties) disque dur (I/O en anglais); la quantit de mmoire vive (RAM) ncessaire.

Le cot sera une synthse entre lutilisation du CPU et le cot des E/S, selon quil sagit daccs squentiels (lecture de plusieurs blocs contigus) ou daccs alatoires (lecture monobloc). Cependant, vous imaginerez aisment que ce cot dpend non seulement de la requte elle-mme, mais aussi des donnes sur lesquelles elle porte. En effet, calculer le salaire moyen dune table contenant 10personnes sera moins coteux que de calculer la mme moyenne sur une table dun million de personnes alors que la requte sera la mme. Pour estimer le cot dune requte, le SGBDR a besoin de dterminer, pour chacune des tapes du plan dexcution, le nombre denregistrements concerns, cest--dire la cardinalit de lopration. Cette cardinalit dpend des donnes elles-mmes mais aussi de limpact de chacune des conditions. Par exemple, une condition qui filtre sur un numro de Scurit sociale naura pas le mme impact sur la cardinalit quune condition portant sur un dpartement ou une anne de naissance. Ce principe se nomme la slectivit, nous ltudierons au Chapitre5, section5.1.3, "Slectivit, cardinalit, densit". Loptimiseur dtermine le cot de chaque plan daction dexcution. Pour cela, sans excuter aucun deux, ni parcourir les donnes, il dfinit les cardinalits de chaque opration partir de statistiques sur les donnes (voir Chapitre5, section5.1, "Statistiques sur les donnes"). Loptimiseur cherche dterminer le meilleur plan ; cependant, la notion de "meilleur" peut, dans certains cas, diffrer en fonction de lobjectif, lOptimizer Goal, qui peut tre de deux types:
First_Rows All_Rows

(premires lignes);

(toutes les lignes).

First_Rows privilgie le temps de rponse pour retourner les premires lignes. Cela peut tre intressant dans le cadre dapplications interagissant avec des utilisateurs.

18

Optimisation des bases de donnes

Pourtant, la meilleure solution choisie pour cet objectif peut se rvler moins intressante si, finalement, on ramne toutes les lignes.
All_Rows, lui, privilgie lutilisation optimale des ressources. Il considre le temps de rponse pour retourner lensemble des lignes.

Il existe aussi des variantes lobjectif First_Rows, ce sont les objectifs First_ Rows_n, o n est une des valeurs suivantes: 1,10, 100, 1000. Dans ce cas, loptimiseur privilgie le temps de rponse permettant de retourner les n premires lignes. Lobjectif de loptimiseur (Optimizer Goal) peut se dfinir diffrents niveaux:

celui de la configuration de linstance, travers le paramtre dinitialisation OPTIMIZER_MODE. celui de la session utilisateur, en agissant sur le mme paramtre:
ALTER SESSION SET optimizer_mode = first_rows_10;

celui dune requte, en utilisant les hints que nous tudierons plus tard:
Select /*+FIRST_ROWS(10) */ * from commandes

Axe 1
tude et optimisation dumodle de donnes
Cette partie aborde laspect conception des bases de donnes en replaant les bases de donnes relationnelles dans le contexte du modle relationnel. Elle a pour but de vous rappeller quelques rgles, mais ne prtend nullement se substituer des ouvrages traitant de la conception de bases de donnes tels que:

Cration de bases de donnes de Nicolas Larrousse (Pearson, 2006); SQL de Frdric Brouard, Rudi Bruchez, Christian Soutou (Pearson, 2008, 2010) (les deux premiers chapitres traitent de la conception de bases de donnes).

Lapplication de mthodes de conception, telles que Merise, permettra davoir une dmarche de conception structure et contribuera obtenir un modle de donnes pertinent et sans cueils de performances majeurs.

2
Modle relationnel
2.1 Prsentation

Les bases de donnes relationnelles que nous tudions sont fondes sur le modle relationnel invent par Edgar Frank Codd en 1970 (dcrit dans la publication ARelational Model of Data for Large Shared Data Banks) et largement adopt depuis. Ce modle sappuie sur lorganisation des donnes dans des relations (aussi appeles "entits"), qui sont des tables deux dimensions:

Les colonnes. Ce sont les attributs qui caractrisent la relation. Les lignes. Aussi nommes "tuples", elles contiennent les donnes.

Lordre des tuples na aucune importance ni signification.


Tableau2.1: Exemple d'une relation contenant des employs

Nom DUPOND DURAND LEGRAND MEUNIER MEUNIER NEUVILLE

Prnom Marcel Jacques Denis Paul Paul Henry

Service Comptabilit Production Ventes Production Achats Ventes

Localisation Toulouse Agen Toulouse Agen Agen Toulouse

22

tude et optimisation dumodle de donnes

Axe 1

Le modle relationnel tablit quil doit tre possible didentifier un tuple de faon unique partir dun attribut ou dun ensemble dattributs, lesquels constituent la cl de la relation. Une cl est dite "naturelle" si un attribut ou un ensemble dattributs la constituent. Dans lexemple prcdent, on constate quil est dlicat den trouver une car se pose le problme des homonymes qui, dans le pire des cas, pourraient travailler dans le mme service. Lorsquune cl naturelle nexiste pas, on introduit un nouvel attribut identifiant qui en fera office. Il sagit, dans ce cas, dune cl technique. Cet identifiant peut tre un numro affect squentiellement. On recourt aussi lutilisation de cl technique quand la cl naturelle est trop grande ou pour des raisons techniques, par exemple des problmes de changement de valeur de la cl lorsquil y a des relations matre/dtails et que le SGBDR ne gre pas la mise jour en cascade. Labsence de cl primaire dans une relation doit tre exceptionnelle (moins de 1% des tables). Lorsque rien ne sy oppose, il faut privilgier lutilisation de cl naturelle. On peut parfois avoir plusieurs cls pour identifier un tuple (cest systmatique si vous ajoutez une cl technique alors quil y a une cl naturelle). Toutes ces cls sont dites "candidates" et celle qui a t retenue pour identifier la relation est dite "primaire".
Tableau2.2: Exemple d'une relation contenant des employs avec un identifiant

Identifiant 5625 8541 4521 8562 7852 6214

Nom DUPOND DURAND LEGRAND MEUNIER MEUNIER NEUVILLE

Prnom Marcel Jacques Denis Paul Paul Henry

Service Comptabilit Production Ventes Production Achats Ventes

Localisation Toulouse Agen Toulouse Agen Agen Toulouse

Un des grands intrts du modle relationnel est quil rpartit lensemble des donnes dans diffrentes relations et tablit des associations entre ces relations au moyen de leur cl primaire. Ce principe permet dviter la duplication dinformation et donc davoir des donnes plus consistantes (voir Tableaux 2.3 et 2.4).

Chapitre 2

Modle relationnel

23

Tableau2.3: Exemple d'une relation "Employ", contenant des employs, avec une association un service

IdEmploy 5625 8541 4521 8562 7852 6214

Nom DUPOND DURAND LEGRAND MEUNIER MEUNIER NEUVILLE

Prnom Marcel Jacques Denis Paul Paul Henry

IdService 100 120 150 120 180 150

Tableau2.4: Exemple d'une relation "Service"

IdService 100 120 150 180

NomService Comptabilit Production Ventes Achats

Localisation Toulouse Agen Toulouse Agen

Le modle relationnel a t conu pour tre utilis avec une algbre relationnelle qui permet deffectuer des oprations sur les entits. Les principales sont:

La jointure. Relie deux entits par leur association. La slection. Filtre les tuples dont les attributs rpondent un prdicat. La projection. Slectionner seulement certains attributs dune entit.

Cette algbre a t implmente puis tendue dans les SGBDR au moyen du langage SQL. Nous nallons pas nous tendre sur la thorie de lalgbre relationnelle qui, mme si elle en constitue les bases, est par moments assez loigne de ce quon peut faire avec du SQL. En termes de gnie logiciel, il est plutt question de modle conceptuel des donnes (MCD). Lorsque celui-ci est bas sur le modle relationnel, on parle alors de modle entit/association (et non pas de modle entit/relation, qui est une traduction errone du terme anglais entity-relationship model). La mthode MERISE, qui a berc

24

tude et optimisation dumodle de donnes

Axe 1

des gnrations dinformaticiens, utilise gnralement ce modle pour reprsenter le MCD. Ainsi, en France, on dsigne souvent par MCD le modle entit/association. La mthode MERISE parle aussi de modle logique des donnes (MLD) qui est trs proche de limplmentation finale en base de donnes. Le MLD est une version indpendante du SGBDR du MPD (modle physique des donnes). Le MLD et le MPD sont souvent confondus, dautant plus quand la base reprsente nest prvue que pour tre implmente sur un SGBDR. Le MCD et le MPD sont deux modles la fois redondants et complmentaires. Ils dcrivent tous deux une base de donnes, mais avec des niveaux de dtail et dabstraction diffrents. Le MCD se veut plus conceptuel, par exemple:

Il dsigne les entits par leur nom logique et non pas par le nom de la table. Les associations sont nommes par un verbe. Il peut contenir des associations entre les entits qui ne seront pas implmentes par la suite sous forme de cl trangre dans la base de donnes. Il ne rpte pas les cls ncessaires aux associations et ne fait pas apparatre le fait quune table est ncessaire pour implmenter une relationM-N.

Figure2.1 Exemple de MCD (diagramme entit-association).

Le MCD se veut indpendant des bases de donnes, il utilise donc des types de donnes "universels". La plupart des outils de modlisation peuvent convertir automatiquement des MCD en MPD mais, gnralement, le rsultat ncessite dtre retouch. Si vous convertissez sans aucune prcaution un MCD en MPD, vous risquez davoir des tables qui sappellent "compose", par exemple, ou un autre

Chapitre 2

Modle relationnel

25

verbe qui a toute sa place dans un MCD mais qui est moins indiqu comme nom de table.

Figure2.2 Exemple de MPD (modle physique des donnes).

Le MPD est propre une base de donnes et permet de gnrer automatiquement les scripts de cration des tables. Il contient les noms des tables, lensemble des champs (qui sappelaient "attributs" dans le MCD) avec leurs types et prcisions, les contraintes dintgrit rfrentielle, les index, etc. Si votre base doit tre importante, prvoyez de passer un peu de temps pour affiner le MPD, laide, entre autres, de ce que nous allons tudier au cours de cet ouvrage. Les partisans du MCD disent que cest une phase indispensable, alors que ses dtracteurs affirment quil ne sert rien. Personnellement, je pense que la vrit doit tre quelque part entre les deux. Cela dpend des habitudes de chaque organisation, de la taille de la base, des outils dont vous disposez et du niveau dabstraction souhait.

2.2

Les bons rflexes sur le typage des donnes

Le typage des donnes parat tre un sujet anodin mais il ne lest pas, et je suis surpris parfois de voir des bases de donnes avec des types incorrectement choisis. La conversion automatique du MCD en MPD peut tre une source de mauvais typage, car les types "universels" ne proposent pas forcment la finesse disponible avec le SGBDR. Il y a principalement quatre familles de types de champs:

numriques; textes; dates et heures; binaires.

26

tude et optimisation dumodle de donnes

Axe 1

Pour les donnes alphanumriques, il ny aura pas trop dambigut. Le nom dune personne devra tre mis dans un champ de type texte. Il existe gnralement trois variantes de types textes qui peuvent avoir des incidences sur le stockage et la manipulation des champs:

les types textes de longueur fixe (gnralement dsigns par char); les types textes de longueur variable (gnralement dsigns par varchar); les types textes de grande capacit (dsigns par text, bigtext ou CLOB).

Les champs de type texte de longueur fixe utilisent systmatiquement lespace correspondant la longueur pour laquelle ils sont dfinis (hormis sur certains SGBDR o le fait dtre NULL noccupe pas despace). Si la chane est plus petite que la longueur de la colonne, elle sera complte par des espaces qui seront ventuellement supprims par le SGBDR ou par la couche daccs aux donnes. Ces champs sont assez peu utiliss mais ils peuvent prsenter un intrt sur des colonnes qui contiennent des valeurs de taille fixe. Lavantage de ce type est quil vite le surcot li la gestion dun champ de longueur variable. Par contre, sa manipulation provoque parfois des comportements droutants pour les dveloppeurs habitus aux types varchar. Le type texte de longueur variable (varchar) est le plus utilis. Il noccupe que lespace ncessaire la donne plus quelques octets pour dfinir la longueur de celle-ci. Les types textes de grande capacit sont rserver aux champs qui en ont vraiment besoin, cest--dire qui ont besoin de contenir plus de 4000caractres (cela dpend des bases). Il en dcoule parfois une gestion du stockage trs spcifique qui peut peser sur les performances et lespace utilis. De plus, certaines oprations sont parfois interdites sur ces types. Tous ces types existent gnralement aussi en version Unicode. Cependant, avec la perce dUNICODE, certaines bases arrivent prsent grer le jeu de caractres UNICODE comme nimporte quel autre jeu de caractres, rendant lintrt des variantes UNICODE des types caractres moins vidents. Concernant les donnes numriques, les SGBDR donnent plus ou moins de choix. Ilsera judicieux de se poser quelques questions sur la nature et ltendue des valeurs manipuler dans ces champs afin de choisir le type le plus appropri. Les principaux types numriques sont:

les types entiers signs ou non signs, sur 8, 16, 32 ou 64bits;

Chapitre 2

Modle relationnel

27

les types dcimaux virgule flottante 32 ou 64bits; les types dcimaux virgule fixe.

Chacun deux occupe plus ou moins despace. Il faut penser que les types virgule flottante font des approximations qui peuvent introduire des dcimales supplmentaires ou en supprimer. Veillez garder de la cohrence avec le type des variables qui manipuleront les donnes dans votre application (si votre application gre un float, il ne faut pas que la base dfinisse un entier 64bits et vice versa). Concernant les identifiants numriques, les types numriques ne sont pas toujours le bon choix. Pour les identifiants numriques squentiels, un type entier est un choix adquat (prendre un type dcimal ne serait pas pertinent). Par contre, pour des identifiants tels que des numros de Scurit sociale (1551064654123), ce nest pas forcment le meilleur choix, car:

Cest une valeur trop grande pour tenir sur un entier 32bits. Les types flottants risquent de lapproximer. Vous navez a priori aucune raison den faire la somme ou la moyenne. Lordre alphabtique des identifiants est le mme que lordre numrique car il y a toujours 13chiffres.

Pour un tel identifiant, je conseille plutt lusage dun type texte de longueur fixe. La prsence de zros en tte didentifiant peut tre un autre problme: ils seront effacs si vous utilisez un type numrique. Par exemple, la valeur 000241 sera stocke, et donc restitue, sous la forme 241 si vous utilisez un type numrique au lieu dun type texte. Concernant les donnes date et heure, il existe, suivant les SGBDR, des types permettant de stocker une date seule ou une date et une heure avec une prcision plus ou moins grande sur la rsolution, allant de quelques secondes des fractions de seconde. Jai vu assez rgulirement des dveloppeurs ne pas utiliser ces types pour stocker des dates mais prfrer des types textes. Largument avanc est que les types date et heure sont parfois pnibles manier aussi bien en SQL que dans les environnements de dveloppement. Je leur concde que cest souvent vrai. En effet, une date est plus difficile manipuler quun entier, mais ce nest cependant pas insurmontable. Il faut juste sy pencher une bonne fois pour toutes, se faire une feuille rcapitulative avec des exemples et, gnralement, aprs tout va bien. Reste nanmoins le problme des fonctions de transformations en SQL qui ne sont pas

28

tude et optimisation dumodle de donnes

Axe 1

portables dun SGBDR lautre. Si votre application doit fonctionner sur diffrents SGBDR, il faudra faire une petite couche dabstraction. Cela montre que le type date complique parfois un peu les oprations, mais quapporte-t-il par rapport un type texte? Si vous stockez dans la base avec une notation ISO (AAAAMMJJ), vous conservez la facult de trier chronologiquement et de travailler sur des intervalles. Par contre, si vous utilisez un format plus franais (ex: JJ/MM/AAAA), le tri et le filtrage par plage seront beaucoup plus compliqus. Bien videmment, le type date vous permettra deffectuer ce genre dopration et aussi des choses quaucun de ces modes de stockage textuel ne permet en SQL, comme soustraire des dates entre elles, ajouter ou soustraire des intervalles de temps. De plus, en termes despace requis pour le stockage des donnes, les types dates seront systmatiquement plus avantageux que leurs quivalents en format texte. Dernier avantage, avec les types dates, vous avez la garantie de navoir que des dates valides dans la base. Ce point est parfois considr comme un inconvnient: il peut arriver que des applications rcuprent des chanes contenant des dates errones, ce qui provoque des erreurs lors du chargement de la base de donnes. Par exprience, je sais quavoir des dates invalides dans les tables pose des problmes; il vaut donc mieux, le plus en amont possible, avoir des donnes valides. Lutilisation dun entier pour stocker une date au format julien (nombre de jours depuis le 1er janvier 4713 av. J.-C.) allie la plupart des atouts du format date (ordre, intervalles, taille) mais prsente linconvnient de ne pas tre trs lisible (2524594 = 1/1/2000). Il nest pas support de faon native par tous les SGBDR et ne permet pas toujours de grer lheure. Lutilisation dun timestamp type unix prsente les mmes caractristiques. Les SGBDR grent gnralement dautres types de donnes, tels que les types binaires permettant de manipuler des images, des sons ou des fichiers, des types XML permettant de stocker du XML et de faire des requtes dessus, et quelques autres types plus spcifiques chaque SGBDR.
2.2.1 Les types sous Oracle

Pour grer les valeurs numriques sous Oracle, on utilise gnralement le type NUMBER avec des prcisions variables suivant que lon souhaite un entier ou une grande valeur dcimale. Sous Oracle, la taille du stockage dpend de la valeur et non pas de la dfinition du champ. Ainsi, stocker la valeur1 prend moins de place que stocker la valeur 123456789,123. Le type NUMBER peut prendre deux paramtres:

Chapitre 2

Modle relationnel

29

precision,

qui correspond au nombre de chiffres significatifs maximal que les valeurs du champ pourront avoir. Il peut prendre une valeur entre1 et38, ce qui correspond aux chiffres de part et dautre du sparateur dcimal. Le symbole* est quivalent la valeur38.

scale,

qui correspond au nombre de chiffres significatifs maximal aprs la virgule. Il vaut0 sil nest pas spcifi: cest alors un moyen de dfinir un type entier.

Le type FLOAT est un sous-type du type NUMBER et ne prsente pas un intrt particulier. Les types BINARY_FLOAT et BINARY_DOUBLE sont, eux, calqus sur les types flottants"C" et occupent respectivement 4et8octets. Les types ANSI (INT, INTEGER, SMALLINT) sont en fait des synonymes de NUMBER(38) qui reprsente un entier. DECIMAL est un synonyme de NUMBER. Les types caractres disponibles sont:
CHAR

et NCHAR pour les textes de tailles fixes limit 2000caractres (NCHAR est la version Unicode). et NVARCHAR pour les textes de tailles variables limits 4000caractres. VARCHAR est un synonyme de VARCHAR2.

VARCHAR2

CLOB et NCLOB pour les textes de grande taille, limits 4Go. Ces types sont trai-

ts comme un LOB (Large OBject). Les donnes sont stockes dans un segment spar, mais sil y en a peu pour un enregistrement et que le stockage en ligne est actif (voir Chapitre 5, section 5.3.1, "Gestion des LOB"), la donne pourra tre stocke comme un VARCHAR. Le type LONG, anctre des CLOB, est obsolte et ne doit plus tre utilis. Les types dates disponibles sont:
DATE, qui permet de stocker date et heure avec une rsolution la seconde, occupe

un espace de 7octets. Il nexiste pas de type date seule, on utilise donc le type date sans spcifier dheure, labsence dheure est traduite par minuit.
TIMESTAMP,

qui permet de stocker date et heure avec une rsolution en fractions de seconde jusqu une nanoseconde. est analogue
TIMESTAMP

TIMESTAMP WITH TIME ZONE

mais stocke en plus la

zone horaire. Les types binaires disponibles sont:


RAW,

pour les binaires de moins de 2000octets.

30

tude et optimisation dumodle de donnes

Axe 1

BLOB, pour les binaires de taille variable, limits 4Go. Concernant le stockage,

il fonctionne comme les CLOB.


LONG RAW, BFILE

anctre de BLOB, ne doit plus tre utilis.

est analogue BLOB si ce nest que les donnes sont stockes dans le systme de fichier du serveur gr par le systme dexploitation et non pas dans un tablespace.
Les types sous SQL Server

2.2.2

Les types numriques disponibles sont:


BIT,

pour les boolens, stock sur 1bit; pour les entiers non signs de 8bits;

TINYINT,

SMALLINT, INT, BIGINT, pour les entiers signs de respectivement 16, 32 et 64bits; DECIMAL FLOAT,
REAL

et NUMERIC, pour les dcimaux virgule fixe, stocks sur 5 17octets suivant la prcision; dcimaux virgule flottante, stock sur 4 8octets suivant la prcision, = FLOAT(24).

Les types caractres disponibles sont:


CHAR

et NCHAR, pour les textes de taille fixe limits 8000caractres; et


NVARCHAR(max),

VARCHAR et NVARCHAR, pour les textes de taille variable limits 8000caractres; TEXT, NTEXT, VARCHAR(max)

pour les textes de grande taille

limits 2Go. Les types dates disponibles sont:


DATE,

qui permet de stocker une date seule (depuis SQL Server 2008);

SMALLDATETIME, DATETIME,

qui permet de stocker date et heure avec une rsolution dune minute, stock sur 4octets; qui permet de stocker date et heure avec une rsolution de trois quatre secondes, stock sur 8octets;

Chapitre 2

Modle relationnel

31

DATETIME2,

qui permet de stocker date et heure avec une rsolution en fractions de seconde jusqu 100nanosecondes, stock sur 6 8octets suivant la rsolution (depuis SQL Server 2008); qui permet de stocker une heure seule (depuis SQL Server 2008). pour les binaires de taille fixe de moins de 8000octets; pour les binaires de taille variable de moins de 8000octets;
VARBINARY(max)

TIME,

Les types binaires disponibles sont:


BINARY, VARBINARY, IMAGE,

pour les binaires jusqu 2 Go, remplac par SQL Server 2005).
Les types sous MySQL

(depuis

2.2.3

Les types numriques disponibles sont:


BOOL,

pour les boolens, stock sur 8bits. pour les entiers non signs, stock sur 8bits.

TINYINT,

SMALLINT, MEDIUMINT, INT, BIGINT, pour les entiers signs de respectivement 16,

24, 32 et 64bits. Il est possible dajouter le mot cl UNSIGNED pour manipuler des entiers non signs. INTEGER est un synonyme de INT.
DECIMAL

et DEC, dcimaux virgule fixe ayant une prcision jusqu 65chiffres significatifs. dcimaux virgule flottante, stock sur 4 et 8octets.

FLOAT, DOUBLE,

Les types caractres disponibles sont:


CHAR,

pour les textes de taille fixe limits 255caractres. pour les textes de taille variable limits 65535caractres.

VARCHAR,

TINYTEXT, TEXT, MEDIUMTEXT et LONGTEXT, pour les textes de taille variable limi-

ts respectivement 255octets, 64Ko, 16Mo, 4Go. Le choix du type permet de fixer la taille du champ interne qui dfinit la taille de la donne. Les types dates disponibles sont:
DATE,

qui permet de stocker une date seule;

32

tude et optimisation dumodle de donnes

Axe 1

DATETIME, qui permet de stocker date et heure avec une rsolution dune

seconde,

stock sur 8octets;


TIMESTAMP, qui permet de stocker date et heure avec une rsolution dune seconde

sur une plage de 1970 2038, stock sur 4octets;


TIME,

qui permet de stocker une heure seule.

Les types binaires disponibles sont:


TINYBLOB, BLOB, MEDIUMBLOB BINARY,

et LONGBLOB, pour les binaires de taille variable limits respectivement 255 octets, 64Ko, 16Mo, 4Go; pour les binaires de taille fixe de moins de 255 Octets; pour les binaires de taille variable de moins de 64Ko.

VARBINARY,

3
Normalisation, base du modle relationnel
3.1 Normalisation

Le but de la normalisation est davoir un "bon" modle de donnes dans lequel les donnes seront bien organises et consistantes. Un des grands principes est que chaque donne ne doit tre prsente quune seule fois dans la base, sinon un risque dincohrence entre les instances de la donne apparat.
Figure3.1 Modle physique des donnes (MPD) de la base de donnes initiale gre par une feuille de tableur.

34

tude et optimisation dumodle de donnes

Axe 1

La normalisation dun modle relationnel sappuie sur des rgles dfinies dans les diffrentes formes normales que nous allons tudier ci-aprs. Nous allons mettre en pratique la normalisation en partant dune petite base de donnes qui a pour but de grer une librairie. Celle-ci, au fil du temps, est devenue une grande librairie et traite des centaines de commandes par jour. La "base de donnes" initiale tait gre sous un tableur et nest donc pas du tout normalise (voir Figure 3.1).
3.1.1 Premire forme normale (1NF)

Pour qu'une entit soit en premire forme normale (1NF), elle doit: avoir une cl primaire; tre constitue de valeurs atomiques; ne pas contenir d'attributs ou d'ensembles d'attributs qui soient des collections de valeurs.

Un attribut qui a des valeurs atomiques nest pas dcomposable en sous-attributs. Par exemple, un attribut NomPrenom nest pas considr comme atomique, puisquil peut tre dcompos en deux attributs: Nom et Prnom. Ne pas contenir dattributs ou densembles dattributs qui soient des collections de valeurs signifie que:

Il ne doit pas y avoir dattributs qui contiennent, en fait, plusieurs valeurs spares par des caractres comme des espaces ou des virgules tels que "Dupond, Durand, Leclerc". Il ne doit pas y avoir densembles dattributs qui soient en fait des listes de valeurs, tels que les attributs Article1, Article2, Article3, etc., de notre exemple.

De tels attributs doivent tre mis dans une entit spare qui aura une association de type1-N avec celle qui contenait ces attributs. Mettons en pratique la premire forme normale sur notre base exemple. Nous allons crer une entit des lignes de commandes pour rsoudre le problme des collections sur les attributs (Livre, Titre, Quantit, Prix) et atomiser les attributs NomPrenom et Adresse. Cela donnera le rsultat suivant qui peut, raisonnablement, tre considr comme 1NF. Nous profitons de cette tape pour enrichir un peu notre modle en ajoutant lattribut ISBN.

Chapitre 3

Normalisation, base du modle relationnel

35

Figure3.2 Modle physique des donnes (MPD) en premire forme normale (1NF).

INFO Il existe plusieurs notations graphiques des modles relationnels. Chaque outil choisit une des notations en prenant parfois des ides d'une autre notation. Les diagrammes prsents ce chapitre sont des MPD sans affichage des types, raliss avec l'outil Toad Data Modeler, avec la notation IE qui utilise les conventions suivantes: Ligne association pleine: association identifiant dpendante; Ligne association discontinue: association non-identifiant dpendante; L'extrmit rond plus triangle dsigne le ct fille de la relation; Rectangle angles droits: table; Rectangle angles arrondis: table fille d'une association identifiant dpendante.

3.1.2

Deuxime forme normale (2NF)

Pour qu'une entit soit en deuxime forme normale (2NF), il faut: qu'elle soit en premire forme normale (1NF); que tous les attributs ne faisant pas partie de ses cls dpendent des cls candidates compltes et non pas seulement d'une partie d'entre elles.

Cette forme ne peut poser de difficults quaux entits ayant des cls composites (composes de plusieurs attributs). Si toutes les cls candidates sont simples et que lentit est 1NF, alors lentit est 2NF. Attention, la rgle sapplique toutes les cls candidates et pas seulement la cl primaire. la Figure3.2, lentit lignescommandes nest pas 2NF car la cl est NoCommande plus Livre. Or, les attributs Titre, Prix et ISBN ne dpendent que de lattribut Livre, donc, seulement dune partie de la cl. Pour transformer ce modle en deuxime forme normale, nous allons crer une nouvelle entit qui contiendra les

36

tude et optimisation dumodle de donnes

Axe 1

informations relatives aux livres. Lapplication de cette forme normale permet de supprimer les inconsistances possibles entre les titres dun mme livre qui aurait t command plusieurs fois, car le modle prcdent permettait davoir des valeurs de Titre diffrentes pour une mme valeur de Livre.
Figure3.3 Modle physique des donnes (MPD) en deuxime forme normale (2NF).

3.1.3

Troisime forme normale (3NF)

Pour qu'une entit soit en troisime forme normale (3NF), il faut: qu'elle soit en deuxime forme normale (2NF); que tous les attributs ne faisant pas partie de ses cls dpendent directement des cls candidates.

la Figure3.3, lentit EnTeteCommandes nest pas en 3NF car toutes les informations relatives au client ne sont pas dpendantes de la commande. Il faut introduire une nouvelle entit, qui contiendra les informations relatives aux clients. Il devrait donc rester dans lentit EnTeteCommandes les attributs DateCommande et MontantCommande. Mais est-ce que lattribut MontantCommande dpend directement de la cl? Apparemment oui, si on considre seulement lentit EnTeteCommandes. Par contre, si on considre aussi ses associations, alors on saperoit que cet attribut est en fait la somme des MontantLigne et ne dpend donc pas seulement de la cl mais de lentit LignesCommandes. Cest ce quon appelle un "attribut driv", cest une redondance dinformation. Pour tre en 3NF, il ne doit pas y avoir dattributs drivs, il faut donc supprimer lattribut MontantCommande. Les attributs calculs partir des colonnes de la mme entit sont eux aussi des attributs drivs et ne sont pas admis dans la troisime forme normale. On pourrait faire la mme remarque pour lattribut MontantLigne de lentit LignesCommandes. Cependant, il y a un argument qui lautorise persister, cest que lattribut MontantLigne est gal Quantit Prix du livre au moment de la commande,

Chapitre 3

Normalisation, base du modle relationnel

37

or, lattribut Prix de lentit CatalogueLivre est le prix actuel du livre. Ce prix est susceptible de changer dans le temps, linformation de prix intgre dans lattribut MontantLigne nest donc pas la mme information que le Prix de lentit CatalogueLivre. Ainsi, lattribut MontantLigne nest pas un attribut driv de lattribut Prix de lentit CatalogueLivre (voir Section 3.2.1).
Figure3.4 Modle physique des donnes (MPD) en troisime forme normale (3NF).

3.1.4

Forme normale de Boyce Codd (BCNF)

La forme normale de Boyce Codd est une version plus contraignante de la troisime forme normale.
Pour qu'une entit soit en forme normale de Boyce Codd (BCNF), il faut: qu'elle soit en troisime forme normale (3NF); que tous les attributs ne faisant pas partie de ses cls dpendent exclusivement des cls candidates.

la Figure3.4, lentit Clients nest pas en BCNF car lattribut Continent dpend certes du client, mais il dpend aussi de lattribut Pays. Pour tre conformes, nous devons crer une nouvelle entit permettant dassocier chaque Pays son Continent.
Figure3.5 Modle physique des donnes (MPD) en forme normale de Boyce Codd (BCNF).

38

tude et optimisation dumodle de donnes

Axe 1

3.1.5

Autres formes normales

Il existe dautres formes normales (quatrime, cinquime et sixime formes normales). Cependant, elles sont un peu plus spcifiques. Tendre vers une troisime forme normale ou une forme normale de Boyce Codd est dj un excellent objectif.

3.2

Dnormalisation et ses cas de mise en uvre

La normalisation est une bonne intention quil est plus que souhaitable dappliquer. Cependant, tout comme lenfer est pav de bonnes intentions, il faut savoir prendre un peu de recul par rapport aux rgles afin de ne pas tomber dans certains excs. Si la normalisation fournit de bons guides, je pense quil faut savoir les remettre en cause sil y a de bonnes raisons de le faire. Le plus important est de se poser les bonnes questions plutt que dappliquer aveuglment des rgles. Lobjet de cette section est de donner quelques rgles pour ne pas respecter celles de la normalisation.
ATTENTION Nous abordons ici la notion de dnormalisation. C'est--dire que nous allons tudier comment enfreindre certaines rgles sur un modle qui les applique. Avant de dnormaliser un modle, il faut d'abord le normaliser.

3.2.1

La dnormalisation pour historisation

Cette premire forme de dnormalisation nen est pas vraiment une. Nous lavons dj aborde, lors de ltude de la troisime forme normale avec lattribut MontantLigne de lentit LignesCommandes. Les formes normales ont pour objectif dviter la redondance de linformation. Si on conoit le modle avec une vision statique, on risque de passer ct du fait que certaines valeurs vont voluer dans le temps et quil ne sera plus possible de retrouver aprs coup la valeur historique. Le prix courant dun article et le prix de ce mme article il y a six mois ne sont pas forcment les mmes. Comme nous lavons dj vu, il sagit de donnes distinctes. Mme si, certains instants, les valeurs sont identiques, elles nont pas le mme cycle de vie. La mthode la plus commune pour grer lhistorique dune valeur consiste recopier linformation dans lentit qui lutilise. Une autre manire possible, et plus

Chapitre 3

Normalisation, base du modle relationnel

39

conforme la logique des formes normales, pour grer ce besoin est de conserver lhistorique de la donne rfrence dans une entit spare et horodate plutt que de rpter la donne chaque instance la rfrenant. Si nous reprenons lexemple du prix qui varie dans le temps, la premire mthode possible consiste recopier le prix dans chaque ligne de commande (voir diagramme de gauche la Figure3.6). On peut aussi crer une entit contenant lhistorique du prix du livre. Ainsi, la donne prix nest pas rpte et on pourra tout moment la retrouver partir de la date de la commande (voir diagramme de droite).

Figure3.6 Deux solutions possibles pour implmenter une gestion des commandes avec un historique des prix.

Dans le cas prsent, mon cur balancerait plutt pour la premire solution ( gauche) car je sais quen termes dimplmentation la seconde solution ( droite) sera plus complique. En effet, quand vous aurez besoin de connatre le prix dune ligne de commande, vous devrez rechercher lenregistrement dhistorique le plus rcent qui a une date antrieure la date de la commande. Cette requte-l nest dj pas trs simple. Si on lajoute au fait quon souhaite calculer le montant total des commandes dun client pour une anne, a devient alors complexe et peu performant avec la seconde solution. La premire solution permet de rpondre cette requte de faon assez intuitive et efficace. Dans dautres contextes, la seconde solution pourrait prsenter plus davantages que la premire. Par exemple, si vous avez de nombreux attributs garder en historique, quils soient volumineux (grands textes descriptifs, photos, etc.) et voluent peu au regard des commandes. La seconde solution permet aussi de connatre les variations de prix dun produit mme si celui-ci na pas t command entre les deux variations. Comme toujours, il faut peser le pour et le contre de chaque solution plutt que chercher forcment la solution mathmatiquement la plus juste.

40

tude et optimisation dumodle de donnes

Axe 1

Certains disent quil ne faut pas dnormaliser pour arranger le dveloppeur et quil faut toujours choisir la solution la plus propre sous peine de se traner des "casseroles" pendant des annes. Cest gnralement vrai, cependant, comme le montre lexemple prcdent, lapplication trop stricte de certaines rgles peut conduire complexifier une application et avoir des impacts substantiels sur les performances. Limportant est de se poser les bonnes questions et de faire vos choix en toute honntet intellectuelle.
3.2.2 La dnormalisation pour performance et simplification en environnement OLTP

La normalisation a pour but, entre autres, dviter la duplication de linformation afin de renforcer la consistance des donnes. Cela peut avoir pour effet de nuire aux performances. Comme nous lavons vu, le modle de droite de la Figure3.6 nest pas adapt pour retrouver aisment lensemble des prix des lignes dune commande. Ainsi, lorsque vous avez besoin dafficher sur une facture le montant total de la commande, il faut faire une requte complique. Imaginons un instant quil y ait une politique, variable pour chaque article, de remises de prix en fonction de la quantit commande. Lajout dun champ MontantRemise pourrait tre considr comme un non-respect des formes normales car il drive des attributs Quantit et CodeArticle. Cependant, je pense que, lorsquun attribut est une valeur qui est drive de faon complexe, on peut raisonnablement ne pas respecter la lettre la troisime forme normale. Abordons prsent le cas des attributs drivs simples mais qui rendent service tels que MontantLigne qui est gal QuantitPrix MontantRemise. On ne peut pas dire que cela soit trs compliqu calculer, du coup ajouter cet attribut nest qu moiti raisonnable. Une solution possible, et mon avis fidle lesprit des formes normales, est dajouter une colonne virtuelle (ou calcule suivant le SGBDR), laquelle contient le calcul et est maintenue par le SGBDR. Ainsi, il est sr que cette information est consistante avec les informations dont elle drive. La limite de ce type de champ est quil ne peut faire des calculs que sur les champs dune mme table. Regardons maintenant un autre cas dattributs drivs simples, des drivs par agrgation, tels que lattribut MontantCommande qui est la somme des MontantLignes la Figure3.3. Sa prsence ne respecte pas la troisime forme normale,

Chapitre 3

Normalisation, base du modle relationnel

41

mais elle peut tre trs pratique pour calculer des indicateurs de chiffres daffaires (CA) en temps rel. En plus dtre pratique, cela sera plus performant que de faire la somme des lignes de chaque commande. Cependant, il faudra maintenir cette valeur, donc faire rgulirement une requte qui recalcule la somme de MontantLignes pour mettre jour lattribut MontantCommande. Cela peut tre acceptable pour le cas de MontantCommande, mais il ne faut pas trop driver, sinon il y a un risque de devoir calculer trop de donnes agrges chaque modification dune donne. En effet, afin de garantir la consistance de ces donnes, chaque fois que vous modifiez un enregistrement de LignesCommandes, vous devez recalculer les valeurs qui en drivent. Par exemple, si vous navez pas t raisonnable, vous pourriez devoir calculer toutes les valeurs suivantes: CA par jour, CA par mois, CA par jour par Livre, CA par mois par Livre, CA par client par an, CA par mois par pays, CA par mois par continent, etc. Vous risquez donc, si vous abusez de la dnormalisation, de plomber srieusement vos performances lors des mises jour des donnes de votre base, alors que votre objectif tait damliorer les performances de votre systme. Lutilisation de vues matrialises que nous tudierons au Chapitre5, section5.3.5, "Les vues matrialises", permet de maintenir ce genre de donnes de faon consistante et relativement performante car les calculs sur ces objets sont faits par variations et non pas par le recalcul complet des totaux (solution qui pourrait tre extrmement coteuse).
INFO Sur la plupart des SGBDR, vous pouvez implmenter des champs calculs l'aide de dclencheurs (triggers). Certains SGBDR proposent aussi le concept de colonnes calcules qui sont, contrairement aux dclencheurs, limites des calculs portant sur la table courante. Sous SQL Server, vous disposez des colonnes calcules persistantes (stockes) ou non persistantes (recalcules la vole) en utilisant la syntaxe suivante dans l'instruction CREATE TABLE. ColCalculee as ColonneA+ColonneB PERSISTED Sous Oracle, depuis la version11g, vous pouvez utiliser les colonnes virtuelles, qui ne sont pas stockes, l'aide de la syntaxe suivante: ColCalculee as (ColonneA+ColonneB) Comme nous le verrons au Chapitre7, section7.4.1, "Impact des triggers", l'utilisation des triggers, mme simples, peut entraner une chute des performances s'il y a beaucoup de LMD.

42

tude et optimisation dumodle de donnes

Axe 1

3.2.3

La dnormalisation pour performance en environnement OLAP

On retrouve souvent les environnements OLAP (OnLine Analytical Processing) sous les noms d"entrept de donnes" (datawarehouse) ou de "systme daide la dcision" (DSS, Decision Support System). En environnement OLAP, la dnormalisation est la rgle, car les formes normales ont t penses pour un environnement OLTP. Lorsquon excute des requtes sur des centaines de milliers denregistrements, faire des jointures tout-va est assez coteux. Quand lessence mme de votre base de donnes est de faire de lanalyse des donnes, cest du gchis de passer son temps refaire les mmes jointures. Dans ce type de base de donnes, on duplique plutt linformation afin de rduire le nombre de jointures et ainsi davoir de meilleures performances. La modlisation de bases OLAP quil nest pas prvu dtudier ici est une science part entire et dpend un peu des outils mis disposition par votre moteur OLAP. Cependant, les techniques doptimisation que nous allons aborder au cours de cet ouvrage sont applicables aux bases OLAP. Dans les bases OLAP, vous entendrez couramment parler de modle en toile et en flocons, de dimensions, de faits. SQL Server et Oracle intgrent des outils pour vous aider manipuler ces concepts. Je vous invite consulter dans la documentation de votre SGBDR les parties relatives aux bases OLAP.
Figure3.7 Exemple de table dnormalise pour un usage OLAP.

En environnement OLAP, vous aurez tendance dupliquer dans les tables de faits les donnes qui vous servent daxe danalyse. Le modle de donnes dune base

Chapitre 3

Normalisation, base du modle relationnel

43

OLAP sera construit en fonction des principaux types danalyses que vous prvoyez de faire. Dans lexemple de la Figure 3.7, nous voyons que nous allons pouvoir faire les analyses suivantes:

par livre; par commande; gographique (Pays, Continent); temporelle (Date de commande, Mois, Anne).

3.3

Notre base de test

Afin dillustrer les concepts que nous allons prsenter tout au long de ce livre, nous allons les appliquer une base de test inspire des modles que nous venons dtudier. Cette base (structure et donnes) est disponible pour les SGBDR Oracle, SQL Server et MySQL sur le site de lauteur ladresse http://www.altidev.com/livres.php.

Figure3.8 Modle physique des donnes de notre base de test.

44

tude et optimisation dumodle de donnes

Axe 1

Tableau3.1: Volumtrie de notre base de test

Nom table clients cmd cmd_lignes livres

Nombre d'enregistrements 45000 1 000000 2 606477 2973

Nous illustrerons quelques mises en uvre avec deux autres bases de tests. La premire, bien connue dans le milieu Oracle, est la base emp/dept du schma SCOTT, elle contient trs peu denregistrements.

Figure3.9 Modle physique des donnes de la base de test emp.

Tableau3.2: Volumtrie de la base de test emp

Nom table emp dept

Nombre denregistrements 14 4

La seconde base de test est une volution de la prcdente qui contient plus denregistrements (voir Annexe C pour plus de dtails) et intgre une table contenant des augmentations appliquer aux employs. Elle sera utile pour tester les requtes modifiant les donnes.

Chapitre 3

Normalisation, base du modle relationnel

45

Figure3.10 Modle physique des donnes de la base de test bigemp.

Tableau3.3: Volumtrie de la base de test bigemp

Nom table bigemp bigdept augmentation

Nombre denregistrements 1400014


400004

1400014

Axe 2
tude et optimisation desrequtes

4
Mthodes et outils de diagnostic
Avant de commencer optimiser une base de donnes, il est important de bien comprendre ce qui se passe et comment agit le SGBDR. Cette phase est fondamentale. Loptimisation dune base de donnes ne se rsume pas juste appliquer quelques recettes de cuisine sans rien comprendre ce que lon fait, ni limpact que chaque action peut avoir.

4.1

Approche pour optimiser

Loptimisation dune base de donnes est une activit qui peut avoir lieu:

de faon curative, cest--dire lorsque les problmes apparaissent lors de limplmentation ou en production; de faon plus prventive lors de la conception de la base.

Afin que des problmes de performances ne surgissent pas durant la phase de production, ce qui nuirait aux utilisateurs, il est important de les anticiper dans les phases amont de la vie de lapplication. Pour cela, il faut intgrer la problmatique des performances dans la dmarche de dveloppement comme toute autre exigence. Cela signifie, entre autres, quil faudra se donner les moyens dvaluer limpact de la croissance du volume. Il nest pas facile, lorsque la base de donnes ne contient que quelques centaines denregistrements, de mettre en vidence de futurs problmes de performances. Il faut donc, en phase de dveloppement et/ou de test, travailler sur une base qui se rapproche de ce que sera la ralit aprs quelques annes de production. Cela peut se faire, en phase de maintenance, partir dune copie des donnes des bases de production et, en phase de cration dune nouvelle application, en produisant des donnes factices laide de gnrateurs de donnes. Si un grand nombre

50

tude et optimisation desrequtes

Axe 2

dutilisateurs est prvu, il sera pertinent de faire, en complment, des tests de charge en simulant des utilisateurs simultans. En phase de conception, vous naurez pas de retours des utilisateurs pour signaler ce qui est lent et donc vous orienter vers les parties qui ont besoin dtre optimises. Faut-il pour autant se creuser la tte sur toutes les tables de la base de donnes? Larponse est oui, pour ce qui est de la normalisation du modle de donnes, et non, pour ce qui est des optimisations au niveau du SGBDR (index, etc.). Gnralement, au moins 80% des donnes vont se concentrer dans moins de 20% des tables, cest donc sur ces dernires quil va falloir concentrer vos efforts. De faon gnrale, une table contenant moins dun millier denregistrements na pas besoin dtre optimise (sauf cas particuliers). Malgr vos efforts durant la phase de conception, il est possible que certaines requtes souffrent de problmes de performances. Dans ce cas, il faudra appliquer la mthode suivante: 1. valuer la situation au moyen de mesures et de lanalyse des schmas dexcution. 2. Appliquer une ou plusieurs solutions techniques. 3. valuer lamlioration. Ce chapitre va vous aider traiter les points relatifs lvaluation. Les prochains chapitres traiteront des solutions techniques possibles voques au deuxime point de cette liste.
4.1.1 Mesurer

Comme la dit William Deming, "On ne peut amliorer que ce que lon mesure!" En effet, si vous essayez diffrentes solutions pour amliorer une requte, comment saurez-vous quelle est la meilleure solution si vous ne faites pas de mesures pour les comparer? Il est ncessaire de trouver des critres tangibles valuer afin de mesurer la progression apporte par les optimisations. Les principaux critres sont:

le temps de rponse; la consommation mmoire; la consommation CPU; le nombre E/S (entres/sorties disque).

Chapitre 4

Mthodes et outils de diagnostic

51

La mesure synthtique la plus pratique est le temps dexcution. Cest un indicateur assez simple dutilisation et cest, de plus, celui qui est ressenti par lutilisateur. Ilfaut cependant excuter la requte plusieurs fois pour valider cette mesure, car le niveau de charge global du systme et dautres lments influent sur ce paramtre. La plupart des environnements graphiques de dveloppement affichent systmatiquement le temps dexcution de la dernire requte. Sous Oracle SQL*Plus, il sactive avec la commande suivante:
set timing on;

Une autre solution, pour mesurer la consommation de ressources, consiste afficher les statistiques relatives lexcution des requtes. la suite de chaque excution, il est possible de rcuprer, dans les vues systme, les statistiques de la dernire excution ainsi que le plan dexcution utilis. Attention, le plan dexcution utilis affiche des cots et des cardinalits estims et non les cots rels. Certains environnements intgrent directement cette fonctionnalit, vous lactivez sur Oracle SQ (raccourci F10 Enregistrer la trace dvelopper, par exemple, travers licne automatique). Dans lenvironnement Oracle SQL*Plus, on peut utiliser le mode AUTOTRACE dont la syntaxe est la suivante:
SET AUTOT[RACE] {ON | OFF | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]] set autotrace on;

Loption ON implique les options explain


explain

et statistics :

affiche le plan dexcution. affiche les statistiques dexcution.

statistics traceonly

permet de ne pas afficher le rsultat lui-mme mais seulement les informations relatives lexcution de la requte.

Lactivation du mode AUTOTRACE ncessite le rle PLUSTRACE, dfini dans le script serveur @$ORACLE_HOME/sqlplus/admin/plustrce.sql :
grant PLUSTRACE to utilisateur;

Le mode AUTOTRACE ncessite la prsence dans le schma de lutilisateur de la table plan_table qui est cre lors de lexcution du script serveur @$ORACLE_
HOME/rdbms/admin/utlxplan.sql.

52

tude et optimisation desrequtes

Axe 2

Ce mode peut aussi requrir laccs certaines vues de la mtabase:


grant select on V_$MYSTAT to utilisateur;

Ou de faon plus large:


grant select_catalog_role to utilisateur; grant select any dictionary to utilisateur;

Listing4.1: Exemple de trace d'une excution sous SQL*Plus


SQL> set autotrace trace; SQL> select * from cmd where noclient>30000; 848099 ligne(s) slectionne(s). Plan d'excution ---------------------------------------------------------Plan hash value: 2368838273 -------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 885K| 15M| 894 (2)| 00:00:11 | |* 1 | TABLE ACCESS FULL| CMD | 885K| 15M| 894 (2)| 00:00:11 | -------------------------------------------------------------------------Predicate Information (identified by operation id): --------------------------------------------------1 - filter("NOCLIENT">30000)

Statistiques ---------------------------------------------------------1 recursive calls 0 db block gets 59557 consistent gets 3142 physical reads 72 redo size 19938918 bytes sent via SQL*Net to client 622345 bytes received via SQL*Net from client 56541 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 848099 rows processed

Chapitre 4

Mthodes et outils de diagnostic

53

tudions de plus prs le rsultat obtenu:


En premier lieu, on obtient le nombre de lignes slectionnes. Ensuite, on a le plan dexcution contenant les valeurs estimes et non pas les effectives. Le plan est complt avec quelques statistiques relles de lexcution. Enfin, se trouvent les statistiques suivantes:
Description Nombre de blocs lus en mmoire aprs accs ventuel au disque Nombre de lectures effectives sur le disque (exprim en blocs) Quantit de REDO ncessaire en octets Octets envoys sur le rseau du serveur vers le client Octets envoys sur le rseau du client vers le serveur Nombre d'changes rseau entre le client et le serveur Nombre de tris effectus compltement en mmoire Nombre de tris ayant requis au moins un accs disque Nombre de lignes retournes

Nom consistent gets physical reads redo size bytes sent via SQL*Net to client bytes received via SQL*Net from client SQL*Net roundtrips to/from client sorts (memory) sorts (disk) rows processed

MS SQL Server
Dans l'environnement SQL Server Management Studio (SSMS), depuis une fentre requte, l'quivalent du mode trace automatique est disponible par l'icne basculante (Inclure le plan d'excution rel ou Ctrl+M). Ce mode affiche, lors de chaque excution, le plan d'excution utilis avec quelques informations statistiques relles en plus des informations estimes.

54

tude et optimisation desrequtes

Axe 2

MySQL
Pour tracer des instructions avec des statistiques depuis la version 5.0.37, vous pouvez utiliser l'instruction SHOW PROFILE. Pour cela, vous devez commencer par activer le profiling avec l'instruction:
set profiling=1;

puis, vous pouvez consulter les informations avec les instructions suivantes:
mysql> show profiles\G *************************** 1. row *************************** Query_ID: 1 Duration: 0.02978425 Query: select max(nom) from clients where noclient>0 *************************** 2. row *************************** Query_ID: 2 Duration: 0.02709625 Query: select max(nom) from clients where noclient<30000 mysql> show profile for query 2; +--------------------+----------+ | Status | Duration | +--------------------+----------+ | starting | 0.000102 | | Opening tables | 0.000012 | | System lock | 0.000004 | | Table lock | 0.000006 | | init | 0.000020 | | optimizing | 0.000010 | | statistics | 0.000034 | | preparing | 0.000029 | | executing | 0.000004 | | Sending data | 0.026828 | | end | 0.000006 | | query end | 0.000004 | | freeing items | 0.000033 | | logging slow query | 0.000001 | | cleaning up | 0.000005 | +--------------------+----------+

Une autre solution consiste utiliser l'instruction SHOW STATUS qui affiche environ 300statistiques sur la session en cours. Pour mesurer l'impact d'une requte, il suffit de purger les statistiques avant d'excuter la requte l'aide de l'instruction:
Flush status;

puis d'afficher les statistiques en filtrant un groupe de statistiques avec l'instruction suivante:
mysql> show session status like 'Select%'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | Select_full_join | 0 | | Select_full_range_join | 0 | | Select_range | 1 | | Select_range_check | 0 | | Select_scan | 0 | +------------------------+-------+

Les groupes de statistiques les plus intressants sont Select, Handler, Sort, Created, Key

Chapitre 4

Mthodes et outils de diagnostic

55

4.1.2

Comprendre le plan d'excution

Le plan dexcution est lexpression par le SGBDR de la mthode daccs aux donnes pour rpondre une requte. Comme nous lavons vu au paragraphe prcdent, il saffiche la suite de lexcution dune requte lorsque la trace automatique est active. On peut aussi le consulter sans excuter la requte en passant par la commande explain plan for puis en lanant le script @?/rdbms/admin/utlxpls. sql. La plupart des outils de dveloppement pour Oracle, y compris loutil gratuit Oracle SQL Developer, intgrent une interface permettant de le consulter. Ci-aprs, la trace dexcution de la requte suivante:
select nom ,titre from clients c join cmd on c.noclient=cmd.noclient join cmd_lignes cl on cl.nocmd=cmd.nocmd join livres l on cl.nolivre=l.nolivre where C.pays='France' and L.editeur='Pearson';

Listing4.2: Plan d'excution avec SQL*Plus


------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 572 | 47476 | 2975 (2)| 00:00:36 | |* 1 | HASH JOIN | | 572 | 47476 | 2975 (2)| 00:00:36 | |* 2 | TABLE ACCESS FULL | LIVRES | 35 | 1470 | 13 (0)| 00:00:01 | |* 3 | HASH JOIN | | 48490 | 1941K| 2961 (2)| 00:00:36 | |* 4 | HASH JOIN | | 18613 | 563K| 1066 (2)| 00:00:13 | |* 5 | TABLE ACCESS FULL | CLIENTS | 841 | 16820 | 171 (1)| 00:00:03 | | 6 | TABLE ACCESS FULL | CMD | 1000K| 10M| 890 (2)| 00:00:11 | | 7 | INDEX FAST FULL SCAN| PK_CMD_LIGNES | 2606K| 24M| 1883 (1)| 00:00:23 | -------------------------------------------------------------------------------------

Predicate Information (identified by operation id): --------------------------------------------------1 - access("CL"."NOLIVRE"="L"."NOLIVRE") 2 - filter("L"."EDITEUR"='Pearson') 3 - access("CL"."NOCMD"="CMD"."NOCMD") 4 - access("C"."NOCLIENT"="CMD"."NOCLIENT") 5 - filter("C"."PAYS"='France')

Le plan dexcution prsente la liste des oprations qui vont tre effectues lors de lexcution, reste comprendre ce que cela veut dire. Nous allons voir ci-aprs les oprations les plus frquemment rencontres.

56

tude et optimisation desrequtes

Axe 2

Figure4.1 Plan d'excution sous Oracle SQL*Developer. Il contient les mmes informations que sous SQL*Plus mais prsentes diffremment.

Il en existe dautres, plus "exotiques", souvent lies une fonction en particulier, consultez la documentation Oracle pour plus dinformation. Mais dcodons dabord le plan dexcution de la Figure4.1: 1. Parcours complet de la table clients en filtrant PAYS='France'. 2. Jointure de type HASH JOIN par la colonne Noclient entre le rsultat de lopration prcdente et la table cmd via un parcours complet de la table cmd. 3. Jointure de type HASH JOIN par la colonne Nocmd entre le rsultat de lopration prcdente et la table cmd_lignes via lindex PK_CMD_LIGNES (la table cmd_lignes napparat pas directement car seules les colonnes Nocmd et Nolivre prsentes dans lindex sont ncessaires). 4. Parcours complet de la table livres en filtrant EDITEUR='Pearson'. 5. Jointure de type HASH JOIN par la colonne Nolivre entre le rsultat de lopration prcdente et le rsultat de lopration3. Le plan dexcution se lit du fond de larbre vers la racine. La colonne Cardinality contient lestimation du nombre de lignes manipules par lopration.
Oprations d'accs aux tables

Full Table Scan. Cette opration est assez simple comprendre: la table est parcourue (scanne) entirement, de faon linaire, dans lordre le plus simple, cest--dire lordre des blocs dans le tablespace. Partition. Opration effectue sur des partitions et non sur la table entire, spcifique de la manipulation de tables partitionnes.

Chapitre 4

Mthodes et outils de diagnostic

57

Table Access By RowID. Cette opration permet un accs direct un enregistrement au sein dun bloc de donnes grce au RowID qui contient ladresse du bloc et loffset de la ligne dans le bloc. Cela a gnralement lieu aprs laccs un index qui fournit le RowID. Cette opration est aussi effectue sur une condition du type
rowid= AAARdSAAGAAAGg0AAA.

Oprations d'accs aux index

Unique Scan. Parcourt larborescence de lindex pour localiser une cl unique. Typiquement utilis sur une condition du type noclient=37569. Range Scan. Parcourt une partie dindex de faon ordonne. Typiquement utilis sur une condition du type noclient between 50000 and 60000. Full Scan. Parcourt un index en entier en respectant lordre de lindex. Fast Full Scan. Analogue Full Scan mais ne respecte pas lordre des donnes. Typiquement utilis lorsquune condition peut tre applique sur un index sans que lordre de tri soit mis en jeu. Par exemple:
select count(*) from clients where mod(noclient, 1000) = 150.

Skip Scan. Utilise les index multicolonnes sans tenir compte des premires colonnes. Dans ce cas, lindex est considr comme un ensemble de sous-index. Bitmap. Utilise un index de type bitmap. Partition. Utilise un index partitionn.
Oprations de jointure

Nested Loop (boucles imbriques). Parcourt les sous-ensembles pour chaque valeur de lensemble de donnes pilotes. Illustrons ce comportement avec la requte suivante:
select * from cmd where noclient in (select noclient from clients where pays='Cameroun' )

La sous-requte va tre lensemble pilote en ramenant une liste de 30clients. Pour chacun de ces Noclient, le SGBDR va excuter la requte principale. Cela quivaut au pseudo-code suivant:
Foreach NoDuClientPilote in (select noclient from clients where pays='Cameroun') select * from cmd where noclient = NoDuClientPilote

58

tude et optimisation desrequtes

Axe 2

Merge Join. Rapproche deux ensembles de donnes tris. Le principe est que deux curseurs parcourent linairement les ensembles tris. Cette solution est performante pour rapprocher deux ensembles dj tris sur les cls de jointure (voir Figure 4.2).
Figure4.2 Illustration d'un Merge Join par les champs N CMD.
N CMD N CLIENT DATECOMMANDE N CMD N LIVRE QUANTITE

14524 14525 14526 14527 14528 14529 14530 14531 14532 14533 14534 14535 14536 14537 14538 14539 14540 14541 14542

106141 131869 83068 120877 34288 103897 63544 92173 18994 22006 46777 103180 56563 107179 102964 77719 121630 44011 81100

16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004

14524 14524 14525 14525 14526 14526 14527 14527 14528 14528 14528 14528 14528 14529 14529 14530 14530 14531 14531

6187 7789 4234 5554 5080 1579 4447 4396 4237 5380 2257 4339 4660 4651 5419 4177 7426 7423 8308

1 1 3 3 3 3 1 4 8 5 6 7 7 1 1 1 4 2 3

Hash Join. Construit une table de hachage permettant daccder plus rapidement aux cls (voir Figure 4.3).
A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 A16 A17 A18 A19 A20 A21 A22 A23 A24 A25 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12 C13 C14 C15 C16 C17 C18 C19 C20 C21 C22 C23 C24 C25 D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 D14 D15 D16 D17 D18 D19 D20 D21 D22 D23 D24 D25 E1 E2 E3 E4 E5 E6 E7 E8 E9 E10 E11 E12 E13 E14 E15 E16 E17 E18 E19 E20 E21 E22 E23 E24 E25 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 G1 G2 G3 G4 G5 G6 G7 G8 G9 G10 G11 G12 G13 G14 G15 G16 G17 G18 G19 G20 G21 G22 G23 G24 G25 H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 H11 H12 H13 H14 H15 H16 H17 H18 H19 H20 H21 H22 H23 H24 H25

Recherche des valeurs dans table hachage

NCMD

NCLIENT

DATECOMMANDE

Construction table hachage


NCLIENT NOM PRENOM

14581 Richards 14584 Farrow 14587 Reeves 14590 Kidman 14593 Palin 14596 Molina 14599 Swinton 14602 Ricci 14605 Damon 14608 Rio 14611 Blades 14614 Bacon

Keith Talvin Heather Xander Jonatha Sheryl Lynn Tracy Gladys Jon Johnnie Trini

Comparaison entre les enregistrements ayant le mme hash code

14524 14525 14526 14527 14528 14529 14530 14531 14532 14533 14534 14535 14536 14537 14538 14539 14540 14541 14542

106141 131869 83068 120877 34288 103897 63544 92173 18994 22006 46777 103180 56563 107179 102964 77719 121630 44011 81100

16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004 16/04/2004

Table ou index A

Table ou index B

Figure4.3 Exemple Hash Join de la forme clients.noclient=cmd.noclient.

Chapitre 4

Mthodes et outils de diagnostic

59

1. On parcourt la table A (clients) car cest celle qui a le moins denregistrements. Avec une fonction de hachage, on calcule le hashcode de chaque cl de la jointure pour construire une table de hachage (hash table). 2. On parcourt la table B (cmd) et, pour chaque valeur de la cl de jointure, on cherche si son hashcode existe dans la table de hachage (sil nexiste pas, cest que cette ligne na pas de correspondance dans lautre table). 3. Si on a trouv une correspondance, on teste pour chaque enregistrement de la tableA correspondant au hashcode si la cl est gale la cl de la tableB. Une fonction de hachage (qui donne le hashcode) est une fonction injective qui donnera toujours le mme rsultat pour une valeur donne, mais plusieurs valeurs dentres pourront donner la mme valeur de sortie. Le but de la table de hachage est de crer une liste de valeurs ordonne et continue, qui permettra de regrouper des petits ensembles de donnes dans chacune de ses cases. Il suffira de comparer chaque cl avec seulement le sous-ensemble des cls qui a le mme hashcode et non pas avec toutes les cls. Idalement, petit ensemble signifiera infrieur ou gal un enregistrement (parfois0, souvent1, parfois plus). Ce souhait impliquera davoir une table de hachage la plus grande possible. Le but de cette technique est de ne comparer chaque enregistrement de la tableB qu peu denregistrements de la tableA. Cette dernire sera forcment la plus petite afin de respecter lobjectif davoir le moins denregistrements correspondants une case de la table de hachage. Outer Join (jointure externe). Ce sont des variantes des jointures prcdentes. Elles suivent le mme principe, si ce nest quon slectionne aussi les lignes qui nont pas de correspondance.
Autres oprations

Union, Intersection, Minus. Effectuent des oprations ensemblistes. Cest gnralement explicite dans la requte. Sort. Effectue un tri. Sort Agregate. Effectue une opration dagrgation (SUM,
AVG, COUNT, etc.).

Filter. Filtre des donnes suivant un prdicat (synonyme de condition).

60

tude et optimisation desrequtes

Axe 2

MS SQL Server
Dans l'environnement SQL Server Management Studio (SSMS), depuis une fentre re(Afficher le plan d'excution estim ou Ctrl+L) qute, vous pouvez utiliser l'icne pour afficher le plan d'excution (voir Figure4.4). La zone d'information jaune dtaillant l'opration apparat si l'on passe le curseur sur une des oprations. Figure4.4
Plan d'excution SQL Server.

Les oprations ne sont pas les mmes que sous Oracle, mais on retrouve les mmes principes.

MySQL
Dans l'outil MySQL Query Browser, vous pouvez cliquer sur l'icne Explain pour afficher le plan d'excution (voir Figure4.5). Figure4.5
Plan d'excution MySQL.

Le plan s'affiche dans la zone du bas. Si vous travaillez en ligne de commande, vous pouvez utiliser EXPLAIN ou EXPLAIN EXTENDED comme illustr ci-aprs. L'utilisation de \G permet d'avoir une prsentation verticale plus pratique lire.

Chapitre 4

Mthodes et outils de diagnostic

61

mysql> EXPLAIN EXTENDED select * from clients where noclient<30000 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: clients type: range possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: NULL rows: 5275 filtered: 100.00 Extra: Using where 1 row in set, 1 warning (0.00 sec)

4.1.3

Identifier les requtes qui posent des problmes

Avant de travailler rsoudre les problmes, il faut correctement les identifier. En premier lieu, il faut identifier les requtes qui posent le plus de problmes et se concentrer sur celles-ci. Diffrentes mthodes existent pour trouver les requtes optimiser.
Utilisation de V$SQL

Une premire manire, qui est la plus basique, consiste utiliser la vue dynamique v$sql qui contient les requtes excutes rcemment ainsi que des informations statistiques sur leur excution. Je vous conseille de mettre des limites pour ne cibler que votre schma et exclure les requtes internes dOracle (Dans l'exemple ci-dessous, la valeur SCOTT doit tre remplace par votre nom de schma).
SELECT * from V$SQL t where LAST_active_TIME is not null and t.PARSING_SCHEMA_NAME ='SCOTT' and upper(t.SQL_TEXT) not like '%SYS.%' and upper(t.SQL_TEXT) not like '%V$%' and upper(t.SQL_TEXT) not like 'EXPLAIN %' order by t.LAST_active_TIME desc

On pourra ajouter des conditions sur des noms de tables mises en jeu, comme dans la condition ci-aprs, pour rduire encore le volume des requtes retournes.
and upper(t.SQL_TEXT) like '%CMD%'

62

tude et optimisation desrequtes

Axe 2

Les colonnes de cette requte les plus intressantes sont les suivantes:

Fetches, Executions. Elles aident reprer les requtes ramenant beaucoup de lignes et celles excutes frquemment. Les deux sont importantes: en effet, une petite requte ayant un mauvais temps de rponse peut devenir pnalisante si elle est excute des milliers de fois. Disk read, Buffer gets. Elles aident trouver les requtes qui ncessitent de manipuler beaucoup de donnes dans la base, mme si elles nen ramnent que trs peu. Sql_text, Full text. Elles contiennent le texte des requtes qui ont t slectionnes grce aux champs prcdemment dcrits.

Laccs la vue v$sql peut ncessiter les privilges suivants:


grant select_catalog_role to utilisateur; grant select any dictionary to utilisateur;

Statistiques au niveau de l'instance

Une autre mthode sappuie sur les outils Statspack ou AWR (Automatic Workload Repository) qui se servent des statistiques au niveau de linstance. Cela dit, sur un serveur trs actif qui fait tourner de nombreuses applications, vous ne trouverez peuttre pas dinformations pour vous aider en rapport avec une application particulire. Le Statspack est un outil en fin de vie qui a pour but de collecter des statistiques au niveau de linstance et, par la suite, den extraire des rapports. Mode demploi rapide: 1. Si ce nest dj fait, installez-le en excutant sur le serveur le script
admin/spcreate.sql. rdbms/

2. Prenez des snapshots en excutant:


exec statspack.snap;

3. Dans Oracle SQL*Plus, excutez le script spreport.sql qui va gnrer des fichiers rsultats dans le rpertoire de travail de SQL*Plus. AWR est le remplaant du Statspack, il donne des informations trs proches de celles du Statspack, en plus complet. Parfaitement intgr la console dadministration OEM (Oracle Enterprise Manager), il est install automatiquement sur une installation standard. Par dfaut, il prend un clich (snapshot) toutes les heures.

Chapitre 4

Mthodes et outils de diagnostic

63

Les fonctions relatives AWR sont disponibles dans la console dadministration web, dans la partie relative linstance, onglet Serveur, cadre Gestion des statistiques, lien Rfrentiel de charge globale automatique. Sur cet cran, vous pouvez visualiser les clichs disponibles et excuter un rapport AWR entre deux clichs de votre choix. Les rapports permettent de visualiser des statistiques sur le niveau de charge ainsi que les vnements les plus significatifs, parmi lesquels les instructions SQL les plus consommatrices de CPU, dE/S ou les plus frquentes. Suite lexcution dun rapport AWR, vous pouvez excuter ADDM (Automatic Database Diagnostic Monitor) qui fera des propositions dactions fondes sur les informations les plus pertinentes du rapport AWR. Dans certains cas, il peut proposer dexcuter SQL Tuning Advisor (voir section4.2.2 de ce mme chapitre) afin de faire des propositions damlioration du SQL.
Suivi des performances de la console web

Une troisime mthode consiste utiliser longlet performance de la base de donnes. Cet cran permet de visualiser les taux dactivit les plus levs en temps rel ainsi que didentifier les sessions et les instructions ayant le taux dactivit le plus lev au moyen du lien "Taux dactivit les plus levs".

Figure4.6 cran de la console d'administration montrant les taux d'activit les plus levs.

64

tude et optimisation desrequtes

Axe 2

Dans la console, de nombreux crans peuvent vous aider trouver les requtes, applications ou utilisateurs, qui consomment le plus de ressources. Ces crans mritent dtre tudis attentivement.
Trace des requtes

Une quatrime manire consiste tracer lexcution de toutes les requtes:

Soit, si cela est possible, en traant les excutions ct application cliente laide des outils de monitoring ct client afin dtudier cran par cran le trafic gnr et le temps de rponse de chacune des requtes. Cette approche est conditionne la disponibilit de tels outils pour votre environnement de dveloppement. Soit, en traant des requtes ct serveur, en utilisant loutil SQL Trace, dtaill la section4.2.4 de ce chapitre.

4.2
4.2.1

Outils complmentaires
Compteurs de performance Windows

Sous Windows, il est facile daccder un ensemble de paramtres permettant daider au diagnostic lors dune chute de performance. Ces donnes sont consultables au moyen des compteurs de performance visualisables au travers du moniteur de performance (il existe des choses plus ou moins analogues sur les autres plates-formes). Cet outil vous permettra de surveiller lusage des ressources matrielles de votre serveur. Les compteurs les plus importants sont:

% processeur. Affiche le taux dusage du CPU. Si lensemble des CPU tend vers 100%, cela signifie que les processeurs ont atteint leur limite de traitement. Pages/s. Indique le niveau dchange entre la mmoire virtuelle et la mmoire physique. Si ce compteur prsente en permanence des valeurs leves, cela signifie que le systme manque de mmoire physique ou que les applications en demandent trop. Octets lus et crits/seconde. Montre le niveau de sollicitation du sous-systme disque.

Chapitre 4

Mthodes et outils de diagnostic

65

Mmoire disponible. Permet de vous assurer que le serveur dispose encore dun peu dair. Gnralement, si la mmoire vive passe sous la barre des 100Mo, cela signifie quelle est sature.

Cet outil permet de travailler au niveau serveur, il ne vous aidera pas dans le diagnostic dune requte mais pour mettre en vidence une saturation au niveau du matriel. Cette saturation peut indiquer que le matriel atteint ses limites, mais les limites elles-mmes peuvent tre atteintes parce quil y a un problme en amont (base mal configure, requtes peu performantes).
MS SQL Server
De trs nombreux compteurs de performances SQL Server sont disponibles. Ils permettent de se faire une bonne ide de l'activit de chaque instance de SQL Server.

4.2.2

SQL Tuning Advisor (Oracle)

Ce module, quon pourrait traduire par "Assistant doptimisation SQL", permet danalyser une requte et den dgager des propositions damlioration. Il est accessible depuis la console web, soit depuis la feuille de calcul SQL, soit depuis les crans de suivi de la performance. Si nous soumettons la requte ci-aprs, nous obtenons les recommandations de la Figure4.7:
select * from clients where codepostal='40321'

Figure4.7 Recommandations sur une requte.

66

tude et optimisation desrequtes

Axe 2

SQL Tuning Advisor propose de visualiser le plan dexcution que cela donnerait en appliquant les recommandations au moyen des icnes de visualisation prsentes dans les colonnes Nouveaux dtails du plan dexcution et Comparer les plans dexcution (voir Figure4.8). Le bouton Implmenter permet de crer directement lindex recommand. Cette fonction peut tre utile, mais elle reste cependant relativement limite et ne propose quune partie des optimisations possibles.

Figure4.8 cran de comparaison des plans d'excution.

4.2.3

SQL Access Advisor (Oracle)

Cette fonction de conseil prsente des similitudes avec SQL Tuning Advisor. La principale diffrence est quelle travaille sur un ensemble de requtes pour proposer ses conseils, alors que SQL Tuning Advisor travaille sur une seule requte la fois. SQL Access Advisor prend en compte le nombre dexcutions de chaque requte. Vous accdez cette fonction par le Centre de Conseil, en choisissant Fonctions de conseil SQL puis SQL Access Advisor.
INFO Il est possible que vous rencontriez quelques difficults excuter une tche SQL Access Advisor. Cela peut venir du fait que vous utilisez un navigateur sur un poste de travail en franais sur une base qui est configure en anglais (voir avec l'instruction ci-aprs). show parameter nls_language

Chapitre 4

Mthodes et outils de diagnostic

67

Si c'est le cas, un workaround rfrenc consiste effectuer l'opration suivante dans votre navigateur (ici expliqu avec Internet Explorer). Dans le menu Outils > Options Internet, cliquez sur Langues, ajoutez la langue "Anglais (tats unis)" et passez-la en premire position. Cela aura pour effet de passer les crans de la console en langue anglaise mais vous permettra de mener terme l'excution de SQL Access Advisor. Dans les conseils obtenus de SQL Access Advisor, il se peut que vous vous demandiez quoi correspond l'action RETAIN INDEX qui suggre le code SQL suivant: /* RETAIN INDEX "UnOwner"."UnIndex" */ Sachez que c'est juste une confirmation de la part de SQL Access Advisor qui estime que votre index est utile et que vous devriez le garder. Ce code SQL est seulement un commentaire, et rien de plus.

4.2.4

SQL Trace (Oracle)

SQL Trace est la mthode historique permettant de tracer lactivit dune base de donnes. Ce nest plus la plus recommande par Oracle qui, prsent, conseille plutt dutiliser la console web. Consquence, cette fonction a trs peu volu depuis plusieurs versions dOracle et nest de ce fait, pas trs pratique mettre en uvre.
Gnrer les traces

Il est possible dactiver la fonction de trace du SQL avec un filtrage aux niveaux suivants:

instance; session utilisateur; identifiant client; service, module, action.

Les traces sont places dans des fichiers stocks sur le serveur dans le rpertoire dsign par le paramtre UDUMP, dont vous pouvez consulter la valeur laide de linstruction suivante:
SHOW PARAMETERS user_dump_dest;

Vous pouvez modifier ce paramtre laide de linstruction:


ALTER SYSTEM SET user_dump_dest = '/nouveau_repertoire_user_dump' SCOPE=both;

68

tude et optimisation desrequtes

Axe 2

Pour avoir des informations plus compltes dans les fichiers de trace, il faut sassurer que le paramtre timed_statistics est true et, le cas chant, le modifier (par dfaut, il est false) laide des instructions suivantes:
SHOW PARAMETERS timed_statistics; ALTER SYSTEM SET timed_statistics = true SCOPE=memory;

Pour activer la trace au niveau instance, vous pouvez excuter une des instructions suivantes:
ALTER SYSTEM SET sql_trace = true SCOPE=MEMORY; EXECUTE DBMS_MONITOR.DATABASE_TRACE_ENABLE(waits => TRUE, binds => FALSE, instance_name => 'orcl');

Pour dsactiver la trace au niveau instance, vous pouvez excuter une des instructions suivantes:
ALTER SYSTEM SET sql_trace = false SCOPE=MEMORY; EXECUTE DBMS_MONITOR.DATABASE_TRACE_DISABLE(instance_name => 'orcl');

Pour les autres niveaux de filtrage (session, identifiant client, service, module, action), vous aurez besoin dinformations complmentaires que vous pourrez consulter dans la vue v$sessions laide de la requte suivante:
select sid,serial#,username,module,action,service_name,client_identifier from V$SESSION

Vous pouvez influer sur la valeur client_identifier depuis lapplication en utilisant la fonction PL/SQL suivante:
dbms_session.set_identifier('VotreIdentifiant');

Pour influer sur les valeurs de module et action depuis votre application, vous pouvez utiliser les procdures suivantes du package DBMS_APPLICATION_INFO:
DBMS_APPLICATION_INFO.SET_MODULE (module_name, action_name); DBMS_APPLICATION_INFO.SET_ACTION (action_name);

Pour activer la trace sur la session courante, vous pouvez utiliser les instructions suivantes qui activent la trace et, optionnellement, y affectent un identifiant permettant de retrouver le fichier de trace plus facilement:
ALTER SESSION SET sql_trace = true; ALTER SESSION SET tracefile_identifier = matrace25;

Chapitre 4

Mthodes et outils de diagnostic

69

Pour stopper la trace:


ALTER SESSION SET sql_trace = false;

Attention, cette instruction requiert le privilge ALTER SESSION qui nest pas donn par dfaut aux utilisateurs. Oracle recommande dailleurs de ne pas laccorder systmatiquement et de faon permanente. Vous pouvez activer la trace dune autre session partir dune des instructions suivantes en utilisant les informations de la vue v$sessions en paramtres:
execute dbms_system.set_sql_trace_in_session(142, 1270, true); execute dbms_monitor.session_trace_enable(session_id => 142, serial_num => 1270, waits => true, binds => false);

Pour stopper la trace, excutez une de ces instructions:


execute dbms_system.set_sql_trace_in_session(142, 1270, false); execute dbms_monitor.session_trace_disable(session_id => 142, serial_num => 1270);

Pour activer et dsactiver les traces SQL avec dautres niveaux de filtrage, choisissez parmi les procdures suivantes du package DBMS_MONITOR :
CLIENT_ID_TRACE_ENABLE( client_id, waits, binds, CLIENT_ID_TRACE_DISABLE( client_id); SERV_MOD_ACT_TRACE_ENABLE(service_name,
waits, binds ,instance_name, plan_stat); module_name, action_name, plan_stat);

SERV_MOD_ACT_TRACE_DISABLE(service_name,
instance_name);.

module_name,

action_name,

Analyser les traces avec tkprof

Nous venons de voir comment capturer des donnes dans des fichiers de trace. prsent, nous allons voir les moyens permettant de les consulter. La premire chose faire sera didentifier votre fichier de trace dans le rpertoire contenant toutes les traces, laide de lheure par exemple. Linstruction ALTER SESSION tracefile_identifier tudie prcdemment pourra vous y aider. Ensuite, lutilitaire tkprof vous permettra de convertir ce fichier de trace binaire (.trc) en fichier texte (.txt) lisible. Linstruction ci-aprs traite cette conversion:

70

tude et optimisation desrequtes

Axe 2

tkprof orcl_ora_2052_MATRACE25.trc orcl_ora_2052_MATRACE25.txt

Dans le fichier texte gnr, vous trouverez les informations suivantes pour chaque requte:
SQL ID : 5x7w56mw30q9x select count(*) from cmd_lignes where nolivre=6262 and remise=7 call count ------- -----Parse 1 Execute 1 Fetch 2 ------- -----total 4 cpu elapsed disk query current -------- ---------- ---------- ---------- ---------0.00 0.00 0 0 0 0.00 0.00 0 0 0 0.06 6.00 8286 8291 0 -------- ---------- ---------- ---------- ---------0.06 6.00 8286 8291 0 rows ---------0 0 1 ---------1

Misses in library cache during parse: 0 Optimizer mode: ALL_ROWS Parsing user id: 81 Rows Row Source Operation ------- --------------------------------------------------1 SORT AGGREGATE (cr=8291 pr=8286 pw=8286 time=0 us) 281 TABLE ACCESS FULL CMD_LIGNES (cr=8291 pr=8286 pw=8286 time=50914 us cost=2317 size=1470 card=210) ********************************************************************************

Par dfaut, si une requte est excute plusieurs fois, elle sera consolide et napparatra quune seule fois dans le fichier rsultat. Le premier tableau de statistiques indiquera combien de fois chaque requte a t excute. Si vous avez activ les statistiques, vous aurez le dtail de chaque opration du plan avec les statistiques (cr = Consistent Read Mode, pr = Buffer Gets). Loption tkprof explain permet de rinterroger la base pour obtenir le plan dexcution de votre requte. Attention, ce nest pas forcment celui qui tait utilis au moment de la trace. Loption tkprof par le SGBDR.
sys=no

permet de ne pas traiter les requtes rcursives effectues

Lutilitaire trcsess permet dagrger dans un mme fichier le rsultat de plusieurs fichiers de trace en fonction du numro de session, client id, service, module, action en vue de les traiter avec tkprof.

Chapitre 4

Mthodes et outils de diagnostic

71

Analyser les traces avec Trace Analyzer

Trace Analyzer, disponible sur Oracle MetaLink dans la note 224270.1, est un utilitaire analogue tkprof qui donne un rapport au format HTML plus pratique exploiter. Il fournit une synthse des instructions les plus consommatrices et, pour chaque instruction, des informations dans une mise en forme agrable. Reportezvous sa documentation pour linstaller. Pour lutiliser depuis SQL*Plus connect avec le compte qui a servi faire la trace, excutez le script trcanlzr.sql avec votre fichier de trace en paramtre.
@D:\Ora\product\11.1.0\db_1\trca\run\trcanlzr.sql orcl_ora_2052_MATRACE25.trc

Ce script gnre un fichier zip qui contient le rapport en format HTML (voir Figure 4.9). Consultez le rpertoire Doc de Trace Analyzer pour avoir plus dinformations et des explications qui vous aideront analyser les rapports.
Figure4.9 Dtail d'une requte dans le rapport gnr par Trace Analyzer.

72

tude et optimisation desrequtes

Axe 2

4.2.5

Outils SQL Server

SQL Server propose aussi des outils pour aider au diagnostic. Lquivalent de loutil de trace est SQL Server Profiler qui permet de capturer le trafic SQL dun serveur.

Figure4.10 cran de SQL Server Profiler.

Lquivalent de la fonction de conseil Oracle SQL Access Advisor est disponible via lassistant de paramtrage du serveur (Database Engine Tuning Advisor).

Figure4.11 cran de l'assistant de paramtrage du serveur.

Chapitre 4

Mthodes et outils de diagnostic

73

4.2.6

Outils MySQL

Sous MySQL, les outils disponibles sont un peu moins nombreux, du moins dans la version communautaire. La version Enterprise propose dans ses variantes les plus volues un outil de monitoring du serveur. Celui-ci, plutt orient production, intgre cependant Query Analyzer, un outil qui permet de suivre les requtes occupant le plus de ressources.

Figure4.12 cran du Query Analyzer.

En cliquant sur une requte, vous pourrez accder quelques statistiques et au plan dexcution. Attention, le Query Analyzer passe par un proxy pour capturer les requtes. Vous devez donc rediriger le flux de requte sur le port du proxy qui les enverra vers le serveur. Si vous ne possdez pas une version Entreprise, il vous reste quand mme quelques solutions pour savoir quelles requtes optimiser. Vous pouvez activer la journalisation de toutes les requtes avec le paramtre log. Ce mode de journalisation ne donne aucune indication relative au temps dexcution, il permet juste de reprer les requtes les plus excutes. Le paramtre log_slow_queries permet dactiver la journalisation des requtes les plus lentes. Ce sont celles qui durent plus de long_query_time secondes ou qui nutilisent pas dindex si log-queries-not-using-indexes est activ. long_query_ time est exprim en secondes et ne peut pas tre infrieur une seconde. Vous ne pourrez ainsi pas configurer de tracer les requtes de plus de 0,2seconde quil serait peut tre pertinent danalyser.

74

tude et optimisation desrequtes

Axe 2

Le fichier journal des requtes lentes est plus complet que le log gnral des requtes, voici un exemple dune entre:
# Time: 100219 10:44:18 # User@Host: root[root] @ localhost [127.0.0.1] # Query_time: 25.421875 Lock_time: 0.000000 Rows_sent: 4026540 Rows_ examined: 140 SET timestamp=1266572658; select c.* from clients c,clients c2 where c.adresse1 like '%A%' and c2. noclient<15000;

On y trouve le texte de la requte ainsi que le temps dexcution. Si vous souhaitez tracer plus de requtes, vous pouvez vous inspirer de la logique du Query Analyzer en utilisant le serveur proxy MySQL disponible sur http://dev. mysql.com/downloads/. Vous devrez le configurer pour quil trace les requtes qui vous intressent. Ce serveur de proxy peut excuter du code LUA pour chaque requte qui transite travers lui. Le rpertoire share\doc\mysql-proxy contient des exemples de scripts qui pourront vous aider et plus particulirement le fichier analyze-query.lua. En vous documentant un peu, vous pourrez apporter quelques modifications ce script en remplaant par exemple les affichages par une criture dans un fichier laide des instructions suivantes:
-- Dclaration au dbut du fichier local logger = io.open("querylog.txt", "a+") -- la place de print(o) logger:write(o) logger:flush()

Adaptez les valeurs de proxy.global.config.analyze_query et, ventuellement, modifiez la condition qui prcde la journalisation par if o then si vous ne souhaitez rien filtrer. Dans le fichier de configuration du proxy, ajoutez cette instruction pour prendre en compte ce script:
proxy-lua-script = share\\doc\\mysql-proxy\\VotreAnalyze-query.lua

Une fois que vous aurez adapt ces scripts, vous pourrez obtenir pour chaque requte les informations ci-aprs, quil ne vous restera plus qu analyser:
# 2010-02-19 10:33:31 [11] user: root, db: livremyisam Query: "select * from clients where adresse1 like '%A%'" Norm_Query: "SELECT * FROM `clients` WHERE `adresse1` LIKE ? " query_time: 1004.00 us

Chapitre 4

Mthodes et outils de diagnostic

75

global(avg_query_time): global(stddev_query_time): global(count): query(avg_query_time): query(stddev_query_time): query(count):

1091.57 us 2087.51 us 7 1004.00 us -1.#J us 1

Le rpertoire share\doc\mysql-proxy contient aussi le fichier histogram.lua qui vous permettra dobtenir un histogramme des requtes. Dautres outils sont disponibles sur les sites suivants:

http://www.mysqlperformanceblog.com/tools/ http://hackmysql.com/

5
Techniques doptimisation standard au niveau base de donnes
5.1 Statistiques sur les donnes

Les statistiques sont fondamentales pour le fonctionnement du CBO (Cost Based Optimizer). Des statistiques errones ou non reprsentatives peuvent le conduire utiliser un plan dexcution inadapt qui pourrait donc entraner des performances moins bonnes que ce quelles pourraient tre. Sous Oracle 10g, le job GATHER_STATS_JOB est prconfigur pour collecter les statistiques. Sous Oracle11g, cest le package DBMS_AUTO_TASK_ADMIN qui gre cette activit. Cette tche est paramtre pour seffectuer durant la plage de maintenance qui est, par dfaut, configure de 22heures 2heures en semaine et de 6heures 2heures le week-end. La base ne sera pas forcment entirement analyse chaque fois. La collecte commencera par les objets qui nont pas de statistiques ou qui ont t le plus modifis. En cas de cration dune table ou si la nature des donnes change de faon significative, il faut forcer la collecte au lieu de simplement attendre la collecte automatique suivante. Cest particulirement vrai en phase de dveloppement alors que le dveloppeur dtruit et recre des tables et charge des jeux de tests diffrents. Ce chapitre prsente la collecte des statistiques. Vous trouverez lAnnexeB des informations plus dtailles sur leur nature.

78

tude et optimisation desrequtes

Axe 2

5.1.1

Ancienne mthode de collecte

Historiquement, il fallait utiliser les commandes suivantes pour collecter les statistiques:
ANALYZE TABLE <NomTable> COMPUTE STATISTICS; ANALYZE INDEX <NomIndex> COMPUTE STATISTICS;

Oracle recommande de ne plus les utiliser pour la partie collecte des statistiques de loptimiseur.
5.1.2 Nouvelle mthode de collecte

prsent, il est conseill dutiliser le package DBMS_STATS, qui a un niveau danalyse plus pouss et fournit donc loptimiseur des informations plus dtailles que lancienne mthode. Ce package permet de grer les statistiques avec les oprations suivantes:

collecte des statistiques (Gathering Optimizer Statistics): dune table (procdure GATHER_TABLE_STATS), dun index (procdure GATHER_INDEX_STATS), dun schma (procdure
GATHER_SCHEMA_STATS), GATHER_DATABASE_STATS);

de toute la base (procdure


effacement de statistiques; transfert de statistiques (export/import); restauration danciennes statistiques; gestion des statistiques des types utilisateurs (user-defined); gestion des statistiques tendues (Oracle11g).

Parmi toutes ces oprations, la collecte des statistiques est lopration la plus utilise. Par dfaut, elle parcourt toutes les donnes des tables analyser. Cette opration peut donc prendre un temps significatif sur de grosses bases de donnes. Dans ce cas, il peut tre intressant de collecter les statistiques par chantillonnage laide du paramtre ESTIMATE_PERCENT, prsent dans toutes les procdures GATHER_*. La collecte des statistiques dune table implique la collecte pour la table, les colonnes et les index associs cette table.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

79

Exemple de collecte des statistiques du schma scott:


execute dbms_stats.GATHER_SCHEMA_STATS('SCOTT');

Les oprations de transfert des statistiques peuvent servir mettre au point des requtes sur une base de test moins remplie, partir des statistiques de la base de production. Loptimiseur utilisant les statistiques pour faire ses choix, il se comportera comme si la base de test contenait les donnes de production. Concernant les statistiques des types utilisateurs (user-defined), elles sont utiles uniquement si vous utilisez des types utilisateurs dans vos tables et les index de domaine. Vous naurez donc normalement jamais besoin des oprations qui y sont associes. Les statistiques sont stockes dans la mtabase et accessibles via des requtes SQL (voir AnnexeB). On peut constater quelles contiennent de nombreuses informations sur les tables, les index et chaque colonne. Les principales informations collectes sur les tables sont:

le nombre denregistrements; lespace occup en bloc; la taille moyenne dun enregistrement. le nombre denregistrements; le nombre de blocs feuilles; des informations relatives au foisonnement (voir AnnexeB, section B.4). le nombre de valeurs distinctes et nulles; les valeurs hautes et basses; la taille moyenne des donnes de la colonne; la densit de la colonne (voir ci-aprs).

Les principales informations collectes sur les index sont:


Les principales informations collectes sur les colonnes sont:


Au-del de leur utilisation par loptimiseur, certaines de ces statistiques peuvent tre utiles pour avoir des informations sur la base de donnes. En effet, laide de ces statistiques, le dveloppeur ou le DBA peut reprer facilement les plus grosses tables, les colonnes qui ne sont jamais remplies,etc.

80

tude et optimisation desrequtes

Axe 2

5.1.3

Slectivit, cardinalit, densit

La slectivit est lestimation de la fraction de lignes slectionnes lors dune opration de filtrage. Elle permet de calculer la cardinalit dune opration qui est gale : (Nombre de lignes Nombre de Valeurs NULL) Slectivit. On dira, par exemple, que la condition NoCmd=123456 sur la table des commandes contenant un million denregistrements a une forte slectivit puisquelle rduit la slection une ligne sur un million et que la condition DateCommande>To_ Date(1/1/2009,dd/mm/yyyy) a une faible slectivit car elle filtre seulement 37% des valeurs (374311lignes sur un million de lignes). On voit que la slectivit dpend de la nature des donnes et de la nature des conditions. Ainsi, lorsquune condition est une galit, la slectivit est gale la densit de la colonne (colonne Density des statistiques).
1 La densit est dfinie par NombreValeurDistincte . On voit que, plus il y a un nombre de valeurs distinctes important, meilleure est la slectivit.

Lorsquune condition est un intervalle (oprateurs BETWEEN, <, >), la slectivit vaut:
taille de ltendue de lintervalle , la taille de ltendue de la colonne tant dtermine taille de ltendue de la colonne

par les colonnes Low_Value et High_Value (les chanes de caractres et les dates sont converties en une valeur numrique). Si lintervalle est ouvert (par exemple, NoCmd la borne du ct ouvert.
> 1000),

on considre quil sarrte

Notez que, par dfaut, le SGBDR considre que les donnes sont linairement rparties. Nous verrons plus tard comment les histogrammes permettent dintgrer le fait que ce nest pas toujours le cas. Dans certains cas, le SGBDR utilise des valeurs fixes pour la slectivit car il na pas dlments permettant de calculer la slectivit. Lutilisation dune fonction implique potentiellement une densit du rsultat de la fonction diffrente de celle de la colonne passe en paramtre. Concernant lutilisation dun LIKE commenant par un caractre % ou _, le SGBDR ne possde aucune statistique sur le fait quune chane contienne telle ou telle sous-chane, il ne peut donc estimer aucune slectivit fonde sur les statistiques. Un LIKE ne commenant

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

81

pas par un % est considr comme un intervalle, ainsi Nom en Nom >=I and Nom<J par loptimiseur.
Condition Fonction(Nom)='XX' Fonction(Nom)<>'XX' Fonction(Nom)>'XX'

like I%

sera converti

Slectivit 1% 5% 5% 5% 5%

Utilisation du binding: Nom>: B (voir Chapitre8, section8.3, "Utilisation du binding") Utilisation de like : Nom like '%I%'

Combinaison des conditions

Lorsquil y a plusieurs conditions, le SGBDR considre quelles sont indpendantes et multiplie donc les slectivits entre elles. Cette logique marche globalement tant que les colonnes sont indpendantes, mais lorsquelles sont corrles, les rsultats sont errons. Prenons un exemple avec la requte suivante, sachant que la ville Berlin est situe dans le pays Germany:
select * from clients where ville='Berlin' and pays='Germany'

Analysons le comportement du SGBDR:


Nombre d'enregistrements dans la table clients Slectivit de pays='Germany' Estimation de pays='Germany' Slectivit de ville='Berlin' Estimation de ville='Berlin' Slectivit combine Estimation de pays='Germany' And ville='Berlin' Nombre rel d'enregistrements vrifiant pays='Germany' And ville='Berlin' 45000 10,1% 4546enregistrements 0,1% 34enregistrements 0,01% (10,1 % 0,1 %) 4enregistrements 34enregistrements

82

tude et optimisation desrequtes

Axe 2

Nous constatons qu'il y a une erreur de facteur8 (4enregistrements au lieu de34), ce qui risque de conduire l'optimiseur choisir un chemin d'excution inadapt dans certaines requtes. Ce problme peut tre contourn avec lutilisation de lchantillonnage dynamique (Dynamic Sampling), activable laide du hint DYNAMIC_SAMPLING (voir Chapitre7, section7.1, "Utilisation des hints sous Oracle").
/*+ dynamic_sampling(AliasDeTable Niveau) */

Le premier paramtre du hint est lalias de la table sur laquelle il faut faire lchantillonnage dynamique. Le second paramtre est le niveau dchantillonnage. Celuici peut prendre les valeurs110: la valeur1 chantillonne sur 32blocs de donnes, les valeurs2 9 chantillonnent de 2 256blocs, la valeur10 analyse toute la table.
select /*+ dynamic_sampling(c 1) */ * from clients c where ville='Berlin' and pays='Germany'

Cette nouvelle version de la requte utilisant le hint DYNAMIC_SAMPLING donne une cardinalit de lopration de32, ce qui est trs proche de la ralit qui est de 34enregistrements.
Donnes non rparties linairement

Nous avons vu prcdemment que, lors de la slection dintervalles, le SGBDR considre par dfaut que les donnes sont rparties linairement entre la borne basse et la borne haute. Cependant, ce nest pas toujours le cas. Cela arrive lorsque les donnes ne sont naturellement pas rparties linairement. Par exemple, dans un annuaire national, il y aura plus de personnes Paris quen Ardche. Cela arrive aussi lors de lutilisation de valeurs spciales comme on peut en retrouver dans certains modles de donnes. Imaginez que vous ayez besoin de pouvoir affecter des employs un dpartement Non affect. Vous donnez ce dpartement un numro spcial, par exemple 9999999, bien en dehors de la plage des numros classiques, compris par exemple entre 0 et 10000, afin de ne pas le confondre avec les autres numros de dpartements (cela aurait aussi pu tre0 ou 999999). Vous vous retrouvez ainsi avec 99,99% des valeurs entre 0 et 10000 et quelques valeurs 9999999. Cependant, loptimiseur, considrant que les donnes sont rparties linairement, estime quentre 0 et 1000 il y a 0,01% des valeurs alors quil y en a plutt 10%.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

83

NbVal 100 Rpartition relle Hypothse optimiseur sans histogramme

Valeurs 0 10 000 9 999 999

Figure5.1 Comparaison de rpartitions relle et linaire.

Afin damliorer les performances de loptimiseur sur des donnes non rparties linairement, le SGBDR met les histogrammes notre disposition. Ils seront un moyen de synthtiser la rpartition des donnes et de rsoudre le problme des valeurs extrmes particulires et, dans certaines limites, celui des rpartitions non linaires des donnes. Il existe deux types dhistogrammes:

de frquence; de distribution.

Lhistogramme de frquence calcule pour chaque valeur distincte le nombre doccurrences. Il est utilis pour les distributions ayant peu de valeurs distinctes (moins de100valeurs). Il est directement utilis pour calculer la slectivit lors des tests dgalit. Lhistogramme de distribution coupe les donnes en ntranches gales et dtermine les bornes de chaque tranche. Normalement, le SGBDR dtectera les colonnes sur lesquelles le calcul dun histogramme est pertinent et dterminera le type dhistogramme en fonction du nombre de valeurs distinctes. Vous trouverez des informations plus dtailles sur les histogrammes lAnnexeB, sectionB.3.

84

tude et optimisation desrequtes

Axe 2

Statistiques tendues (11g)

Oracle 11g introduit la notion de statistiques tendues qui permet de crer des statistiques (y compris des histogrammes) sur des ensembles de colonnes ou des expressions en utilisant la fonction DBMS_STATS.CREATE_EXTENDED_STATS (ownname, tabname, extension). ownname et tabname permettent de dsigner la table et extension contient soit une liste de colonnes entre parenthses spares par des virgules, soit une expression entre parenthses. Cette fonction retourne le nom de la statistique et nest donc pas utilisable directement avec linstruction EXEC mais peut tre appele depuis une instruction SELECT:
Select dbms_stats.create_extended_stats(null,'CLIENTS','(PAYS,VILLE)') AS NomStat from dual;

Cette instruction a pour effet de crer une statistique sur la combinaison de colonnes Pays,Ville de la table clients du schma courant. Nous forons le calcul dun histogramme sur cette colonne (opration qui ne sera gnralement pas ncessaire):
exec dbms_stats.gather_table_stats(null,'clients',method_opt => 'for columns SYS_STUNUIEHWAFAS55IIEQVJJF#W$ size 254');

SYS_STUNUIEHWAFAS55IIEQVJJF#W$ est la valeur retourne par linstruction SELECT de cration de la statistique tendue ou par la requte suivante qui permet de rcuprer le nom dune statistique tendue.
Select dbms_stats.show_extended_stats_name(null,'clients','(PAYS,VILLE)') AS NomStat FROM dual;

Une fois lhistogramme cr et les statistiques actualises, si on excute nouveau la requte suivante:
select * from clients where ville='Berlin' and pays='Germany'

nous pouvons constater que lestimation par loptimiseur de la requte est prsent de 41enregistrements au lieu de 4enregistrements initialement estims ce qui est plus proche de la ralit qui est de 34lignes. Cependant, cette estimation est moins bonne que celle faite par lchantillonnage dynamique mais elle est moins coteuse. Nous avons vu prcdemment que lutilisation de fonctions dans des prdicats conduisait loptimiseur utiliser des valeurs prdfinies. Il estime ainsi que la requte ci-aprs retourne 1% des enregistrements de la table:
select * from clients where upper(adresse1)='887 PONCE STREET'

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

85

Si nous crons une statistique sur lexpression et si nous collectons les statistiques de la table clients, nous constatons que loptimiseur estime prsent correctement quil ny a quune seule ligne slectionne, ce qui est bien le cas:
select dbms_stats.create_extended_stats(null,'clients','(upper(adresse1))') from dual; exec dbms_stats.gather_table_stats(null,'clients');

MS SQL Server
Sous SQL Server, les statistiques ne sont pas systmatiquement calcules pour chaque colonne, par contre, elles intgrent systmatiquement un histogramme sur les cls d'index primaires et secondaires. Les instructions CREATE STATISTICS et UPDATE STATISTICS permettent de crer et de mettre jour des statistiques manuellement. SQL Server donne, comme les statistiques tendues d'Oracle11g, la possibilit de calculer des statistiques sur des combinaisons de colonnes afin de rsoudre le problme de la mauvaise estimation des combinaisons de conditions.

MySQL
MySQL intgre aussi des statistiques et des histogrammes. L'instruction ANALYZE TABLE permet de forcer la collecte des statistiques. Certaines donnes des statistiques sont consultables en interrogeant la table INFORMATION_SCHEMA.STATISTICS mais il y a bien plus d'informations que celles prsentes dans cette table indpendante des moteurs, car la gestion des statistiques est propre chaque moteur.

5.2

Utilisation des index

Un premier type doptimisation consiste mettre en place des objets ddis loptimisation des tables: les index. Sous Oracle, ils peuvent tre soit de type B*Tree soit de type bitmap. Leur action est gnralement assez efficace, sans pour autant que leur mise en place ncessite beaucoup de changements au niveau de lapplication. Le tout sera de choisir le type dindex le plus adapt la situation. Les index prsentent lavantage de pouvoir tre galement mis en uvre au sein de logiciels raliss par des tiers et pour lesquels vous navez pas accs au code source. Les index, dune manire gnrale, permettent damliorer parfois considrablement les performances en lecture, mais ils peuvent lgrement dgrader les performances en criture car le SGBDR doit les maintenir en plus des tables lors

86

tude et optimisation desrequtes

Axe 2

des modifications des donnes indexes (insertion, modification de la cl dindex, suppression de lenregistrement). Sur des tables qui ont des accs en criture trs concurrents, la mise jour des index peut provoquer des contentions daccs ceuxci et donc des latences dcriture.
5.2.1 Index B*Tree

Utiliss historiquement par les bases de donnes relationnelles, les index B*Tree sont prsents dans de nombreux SGBDR. Leur principe est de contenir les valeurs des cls de lindex de faon ordonne dans une structure arborescente. Ainsi, ils permettent de trouver trs rapidement une valeur prcise en parcourant larbre de la racine vers les feuilles et non pas en recherchant la valeur dans lensemble des enregistrements de la table. De plus, les feuilles sont chanes entre elles (voir Figure5.2). Aussi, lorsquil est ncessaire de parcourir lindex squentiellement, on passe de feuille en feuille sans devoir remonter au niveau des branches. Un index B*Tree porte sur une ou plusieurs colonnes quon appelle "cls de lindex". Suivant le type de lindex, les cls doivent tre uniques (dans le cas dindex uniques) ou peuvent contenir des doublons. Elles peuvent tre des champs de type numrique, date ou chane de caractres mais pas de type BLOB ou CLOB. Lors de la cration de lindex, on spcifie pour chaque champ de la cl son ordre de tri qui, par dfaut, sera ascendant (ASC) mais peut tre dcroissant (DESC) comme dans la clause ORDER BY de linstruction SELECT. Pour comprendre le fonctionnement, prenons un exemple. Pour obtenir lenregistrement ayant pour cl la valeur 1015 dans lindex B*Tree reprsent la Figure5.2, le SGBDR va procder de la manire suivante: 1. Il parcourt le bloc racine jusqu ce quil rencontre une valeur suprieure. 2. Il va sur le bloc point par la valeur qui prcde, ce qui le conduit au premier bloc branche. 3. Dans le bloc branche, il rpte la mme opration, ce qui le conduit un bloc feuille. 4. Dans le bloc feuille, il recherche la valeur. Sil ne la trouve pas, il sarrte la premire valeur suprieure rencontre et renvoie linformation signalant que la valeur recherche nexiste pas dans la table. Sil la trouve, lentre dindex point permet dobtenir le RowID de lenregistrement correspondant.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

87

5. Le RowID permet de rcuprer lenregistrement dans le tas (heap).


1 000 2 000 15 000 16 000 20 000 50 000 150 000 240 000 35 000 47 000 1 700 1 900 ROWID ROWID 1 999 BERGER LEGRAND COMMERCIAL MANAGER 20 000 21 000 1 000 1 015 ROWID ROWID 2 586 325 MARTIN GUY COMMERCIAL MANAGER 0 1 998 999 ROWID ROWID ROWID ROWID 4 521 582 874 LECLERC DUPOND ROCHE OPRATEUR

COMMERCIAL

COMMERCIAL MANAGER

1 015 BERTHIER

Bloc Racine Root Blocks

Blocs Branche Branch Blocks

Blocs Feuille Leaf Blocks

Table Heap : Donnes non ordonnes

Le RowID permet de pointer sur les lignes stockes dans le Tas

Figure5.2 Exemple de parcours d'un index B*Tree.

On constate que nous avons besoin de lire seulement trois blocs de donnes dindex plus un bloc de donnes dans la partie tas de la table pour obtenir lenregistrement, alors quun parcours complet de la table aurait ncessit daccder tous ses blocs. La hauteur de larbre est variable mais excde rarement trois ou quatre niveaux. Si on considre quun bloc non feuille peut pointer sur 100 500blocs (cela dpend de la taille de la cl), lexemple prcdent (dune hauteur de trois) pourrait avoir 10000 250000feuilles. La hauteur de larbre a une progression logarithmique par rapport au nombre denregistrements dans la table. Puisque le nombre daccs ncessaires pour accder un lment dpend de la hauteur de larbre, il est donc lui aussi logarithmique. Sans index, sur une table de nlignes, il faut en moyenne parcourir n/2lignes pour trouver une ligne unique et nlignes pour trouver toutes les occurrences dune valeur

88

tude et optimisation desrequtes

Axe 2

dans une colonne non unique alors que, dans un index, il faut en moyenne parcourir une proportion de log(n) lignes pour trouver une ligne. Par exemple, pour une table dun million denregistrements, sans index il faudra parcourir 1000000 denregistrements alors quavec un index il suffira de parcourir environ 30enregistrements. tant donn la progression logarithmique, accder un enregistrement en passant par une cl indexe sur une table de 10millions denregistrements ne ncessitera pas beaucoup plus daccs que sur une table de 10000enregistrements. Par dfaut, toutes les cls primaires ont un index B*Tree unique qui est cr automatiquement lors de la dclaration de la cl primaire. Nous venons de voir que, plus il y a denregistrements dans une table, plus le gain est grand. Le corollaire est vrai aussi: moins il y a denregistrements dans une table, moins lintrt dun index est grand. En effet, sur des petites tables moins de 1000lignes et ayant des lignes de petite taille, il nest pas pertinent dajouter des index. Lorsque des index sont prsents mais inutiles, ils ne servent pas car loptimiseur ny voit aucun intrt. Ils sont par contre maintenus et occupent de lespace. Nous avons vu que la dernire tape consiste rcuprer lenregistrement partir du RowID obtenu dans le B*Tree. Cette opration est plutt performante puisque le RowID contient ladresse du bloc contenant lenregistrement. Cependant, lorsque plusieurs valeurs sont recherches par le biais de lindex, le SGBDR fait des va-etvient entre lindex et le tas qui peuvent, finalement, tre assez coteux. Donc, si loptimiseur estime quil va rcuprer travers lindex plus de 5% des donnes de la table, il choisira de ne pas lutiliser. En effet, au-del de ce seuil (approximatif), les performances risquent de se dgrader et il sera moins performant dutiliser lindex que de ne pas lutiliser. Le nombre de lignes rcupres dans lindex dpend soit de la nature des donnes, soit de la nature des conditions. Ainsi, il ne sera pas pertinent de placer des index sur des colonnes qui ont beaucoup de valeurs dupliques (cest--dire peu de valeurs distinctes) puisque, quelle que soit la condition sur ce genre de colonne, loptimiseur estimera que trop de lignes seront rcupres pour que cela soit intressant. De la mme faon, il nest pas surprenant quun index ne soit pas utilis sur des conditions peu slectives qui auraient pour effet la rcupration dun grand nombre de lignes. Loptimiseur dcidera de lusage dun index en fonction de lestimation quil aura faite du nombre de lignes quil va rcuprer. Cette information dpend de limage que loptimiseur a des donnes et de sa capacit estimer la slectivit des conditions. On voit ici tout lintrt davoir des statistiques fidles aux donnes.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

89

Il existe cependant un cas o, mme sil y a un grand nombre denregistrements concerns, loptimiseur choisira dutiliser lindex coup sr : les requtes o le parcours seul de lindex suffit obtenir la rponse.
select count(*) from clients where noclient between 10000 and 100000

Dans lexemple prcdent, le parcours de lindex de la cl primaire (Noclient) suffit pour rpondre la requte. Il est donc utilis malgr le fait quil rcupre 60% des enregistrements. La requte suivante, elle, qui ncessite davoir accs au tas de la table pour tester le champ Nom, nutilise pas lindex, car les va-et-vient entre lindex et le tas sont trop pnalisants sur un tel volume.
select count(*) from clients where noclient between 10000 and 100000 and Nom is not null

Les index contenant les valeurs des cls de faon ordonne, ils pourront aussi tre utiliss pour les tris. Des tris peuvent tre ncessaires dans diffrentes situations, telles que lutilisation dune clause ORDER BY, DISTINCT ou GROUP BY dans une requte ou le recours par loptimiseur des jointures de type Sort-Merge. Notez quun index class de faon ascendante pourra tre utilis aussi bien pour des tris ascendants que descendants, la diffrence entre le sens du tri de lindex et celui du tri demand nest gnralement pas significative.
ATTENTION L'utilisation d'index a un impact lors des accs en criture. Le cot de maintien des index est relativement faible mais, s'il y en a beaucoup et que la table subisse de nombreuses modifications, cela peut finalement devenir significatif. Sur un autre plan, les index occupent de l'espace de stockage. Cet espace est, pour simplifier, celui qui est requis pour les feuilles et qui correspond l'espace ncessaire pour les valeurs des cls plus 1RowID par enregistrement. Il peut tre significatif, voire dpasser l'espace de la table si toutes les colonnes sont indexes ou s'il y a de nombreux index. Si vous avez un doute sur le fait qu'un index soit utilis, vous pouvez le mettre sous surveillance l'aide de l'instruction suivante: alter index Nom_Index monitoring usage; puis vrifier, quelques jours ou semaines plus tard, s'il a t utilis depuis l'activation de la surveillance en consultant la colonne Used de la requte suivante: SQL> select * from v$object_usage;
INDEX_NAME TABLE_NAME MONITORING USED START_MONITORING END_MONITORING --------------- -------------------- ---------- ---- ------------------- ------------------IS_CLIENTS_NOM CLIENTS YES NO 01/22/2010 10:48:32

90

tude et optimisation desrequtes

Axe 2

Combinaison des index B*Tree et index composites

De faon gnrale, un seul index B*Tree peut tre utilis par accs une table. Si le plan dexcution ncessite plusieurs accs la mme table (autojointure, par exemple), des index diffrents pourront tre utiliss pour chaque accs. Cela signifie que si une requte contient deux conditions sur deux colonnes indexes sparment, alors seulement lindex le plus pertinent sera utilis et le second ne servira rien. Dans des cas comme celui-l, il peut tre intressant dutiliser des index composites (aussi appels index "multicolonnes") qui permettront dindexer plusieurs colonnes. Lordre des colonnes a son importance, nous allons lillustrer par quelques exemples: Un index composite Pays,Ville sera trs efficace dans les cas suivants:
where where where order Pays='France' and ville='Toulouse' Pays='France' order by ville Pays='France' group by ville by pays,ville

Moyennement efficace dans les cas suivants:


Where ville='Toulouse'

Un index composite Ville, Pays sera trs efficace dans les cas suivants:
where Pays='France' and ville='Toulouse' Where ville='Toulouse'

Moyennement efficace dans les cas suivants:


where Pays='France' order by ville

Inefficace dans les cas suivants:


order by pays,ville

Un index composite sera le plus efficace dans les cas suivants:


prsence de conditions sur toutes les colonnes de lindex; prsence de conditions sur toutes les premires colonnes de lindex; ncessit dun tri suivant lordre de lindex; prsence dune combinaison entre une condition sur les premires colonnes de lindex et un tri suivant lordre de colonnes restantes de lindex.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

91

Un index composite sera peu efficace mais potentiellement intressant malgr tout dans les cas suivants:

Sil y a des conditions sur des colonnes dun index qui ne soient pas conscutivement les premires de lindex. Dans ce cas, loptimiseur pourra dcider de faire un Skip Scan de lindex. Un tri sur les premires colonnes et des conditions sur les colonnes restantes de lindex car dans ce cas lindex devra tre parcouru entirement de faon squentielle.

Un index composite sera inefficace dans de nombreux cas, mais plus particulirement si la requte ncessite un tri sur les colonnes de lindex mais dans un ordre diffrent de celui de lindex.
Cas disqualifiant les index

Nous avons vu que loptimiseur dcidait dutiliser les index quand il pensait que leur usage allait amliorer les performances. Il faut cependant avoir en tte quil existe des cas pour lesquels les index ne seront pas utiliss, car ils sont inutilisables. Lutilisation de like %..., cest--dire un LIKE dont le masque commence par une chane libre, ne permet pas dutiliser un index en mode Unique Scan ou Range Scan. Lutilisation de fonctions ou plus gnralement dexpressions sur les colonnes empche celle des index. Nanmoins, lutilisation dindex sur fonction que nous tudierons plus tard permet dapporter une solution cette limitation si ncessaire. Par exemple, les instructions suivantes empchent lutilisation des index sur les colonnes Noclient et Ville.
select * from clients where noclient*10=40000 ; select * from clients where upper(Ville)='PARIS' ;

INFO Une condition entrant dans un des cas disqualifiants pourra tre applique malgr tout surl'index si l'optimiseur a dtermin pour d'autres raisons que l'index pouvait tre intressant.

92

tude et optimisation desrequtes

Axe 2

Quelles colonnes indexer?

Souvenez-vous, les cls primaires sont, par dfaut, indexes, mais quelles autres colonnes est-il pertinent dindexer? On la vu, les index ont un cot, aussi bien en termes de ressources pour les maintenir jour quen espace occup. Il nest donc pas intressant de les maintenir sils ne servent quasiment jamais. Je vous conseille donc dindexer: Les colonnes les plus utilises dans les clauses WHERE sans quelles entrent dans les cas disqualifiants. Les colonnes les plus utilises dans les jointures. Cela pourra favoriser lusage de Sort Merge Join et rendra les Nested Loop plus performantes. Pour les Hash Join, lintrt sera de constituer la table de hachage (hash table) partir de lindex plutt que la table. Les colonnes qui ont une densit (nombre valeurs distinctes/nombre lignes) faible (infrieure 5%) en relation bien sr avec le premier point. Inutile de crer des index qui ne servent rien. Les colonnes filles de cl trangre (Foreign Key) si la table mre subit des DELETE. En effet, chacun deux provoquera une requte sur ses tables filles pour contrler le respect des contraintes dintgrit rfrentielle (CIR).

Mise en uvre

La syntaxe de base permettant de crer un index et un index unique est la suivante:


create index <Nom_Index> on <NomTable>(<col1>[,<col2>,]) create unique index <Nom_Index> on <NomTable>(<col1>[,<col2>,])

Nous avons dj tudi limpact des histogrammes sur les statistiques. Nous allons tester ici comment cela va se traduire par lutilisation ou non dun index. Par exemple, si nous crons un index is_clients_pays sur la colonne Pays de la table clients laide de linstruction suivante:
create index is_clients_pays on clients(pays);

et que nous testions la requte suivante avec et sans histogramme:


select * from clients where pays='Cameroun'

la Figure5.3a, la slectivit du prdicat est estime par la densit de la colonne 2% avec un fort foisonnement, et lindex ne suffit pas rpondre. Loptimiseur dtermine donc quil sera moins coteux de faire un Full Table Scan.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

93

la Figure5.3b, lhistogramme de frquence permet de dterminer une slectivit plus forte du prdicat sur la colonne Pays 0.07%. Loptimiseur dtermine donc quil est plus intressant dutiliser lindex is_clients_pays. Nous remarquons que cela rduit considrablement les Consistent Gets en les divisant par20.
Figure5.3a Sans histogramme.

Figure5.3b Avec histogramme.

Si nous excutons la mme requte avec pays=USA, alors lhistogramme retourne une estimation de 40% des enregistrements. En toute logique, loptimiseur dcide deffectuer un Full Table Scan puisque lutilisation de lindex sur un tel pourcentage de la table serait pnalisante. On constate bien que le plan dexcution dpend de la nature des conditions mais aussi des donnes des conditions et de la table.

94

tude et optimisation desrequtes

Axe 2

ASTUCE Le SGBDR fabrique automatiquement l'histogramme sur la colonne Pays. Afin d'empcher sa cration pour les besoins de notre dmonstration, nous excutons: execute dbms_stats.gather_table_stats (user,'clients',cascade => true, method_opt => 'for columns pays size 1'); La cration d'un histogramme sur un seul intervalle a pour effet d'empcher la cration de ce dernier. Cependant, c'est parfois le cas inverse qui se produit. Ainsi, si Oracle ne cre pas d'histogramme sur une colonne alors que vous pensez que cela serait pertinent, vous pouvez forcer l'opration l'aide de l'instruction suivante. Il est cependant probable que l'histogramme ne sera pas conserv; lors du prochain calcul des statistiques, il faudra donc intgrer cette instruction un job priodique: execute dbms_stats.gather_table_stats (user,'clients',cascade => true, method_opt => 'for columns pays size 254');

Compression d'index

La compression permet dviter la rptition des valeurs des premires colonnes de la cl dans un index composite et, ainsi, de rduire le nombre de blocs manipuler. Cela amliore lefficacit de lindex. La compression ntant possible que sur les n-1 premires colonnes dun index, cette fonction est rserve aux index composites. Son objectif est de faire gagner de lespace dans les feuilles afin den rduire le nombre. Compresser des colonnes avec peu de doublons pourra entraner une perte defficacit. Exemple dun index compress:
Create index IS_CLIENTS_PAYS_VILLE on Clients(Pays,ville) compress 1;

Cet index compressera les pays qui ne seront rpts quune seule fois par feuille.
MS SQL Server
SQL Server 2005 ne propose pas de mcanisme de ce genre. SQL Server 2008 introduit une compression analogue celle des tables que nous tudierons la section5.3.1 de ce chapitre.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

95

MySQL
Le moteur MyISAM offre la possibilit de compresser les index l'aide de l'option PACK_ KEYS configure au niveau de la table. Par dfaut, si PACK_KEYS n'est pas mentionne, les npremiers caractres communs des chanes de caractres sont compresss. PACK_KEYS=1 force en plus la compression des valeurs numriques. PACK_KEYS=0 dsactive cette fonction. Le moteur InnoDB ne propose pas de compression d'index suivant le mme principe, mais plutt une compression des pages d'index et de table que nous tudierons la -section5.3.1 de ce chapitre.

Comportement des index avec les valeurs nulles

Les SGBDR ont rgulirement des comportements droutants ds quil sagit de manipuler les valeurs nulles, et lutilisation des index nchappe pas la rgle. Le SGBDR Oracle nindexe pas les lignes contenant des NULL sur les premires colonnes pour lesquelles toutes les colonnes prsentes dans lindex sont nullables (cest--dire qui ne sont pas dclares comme NOT NULL). Cela signifie quun index monocolonne ne grera jamais les valeurs nulles, il ne sera donc jamais utilis sur un prdicat IS NULL. Si un index est compos de plusieurs colonnes et quau moins une de ces colonnes soit dsigne NOT NULL, le prdicat IS NULL pourra lutiliser. Cest un cas assez restrictif, donc retenez plutt que, en gnral, les valeurs nulles ne fonctionnent pas avec les index. La valeur nulle est souvent utilise comme valeur spciale. Par exemple, dans notre table des commandes, nous aurions pu avoir une colonne DateLivraison et rechercher les commandes non livres avec le prdicat DateLivraison IS NULL. Nous aurions pu penser quen mettant un index sur cette colonne, la recherche aurait t performante, mais nous nous serions tromps. Dans un cas comme celui-ci, deux solutions soffrent nous: la premire est dutiliser un champ EtatCommande, la seconde consiste ajouter un champ NOT NULL dans lindex B*Tree. Il faudra donc, si cest possible, viter dutiliser la valeur nulle comme valeur spciale ou alors crer un index composite qui englobe en plus de cette colonne une colonne qui nest pas nullable.

96

tude et optimisation desrequtes

Axe 2

Afin de vrifier ce que nous venons dexpliquer, regardons ce quil se passe si nous crons un index sur la colonne Email et que nous recherchions les clients nayant pas dadresse e-mail:
Create index IS_CLIENTS_EMAIL on Clients(email); select * from clients where email is null;

Figure5.4a Plan d'excution d'une requte IS NULL n'utilisant pas l'index.

Nous constatons que lindex is_clients_email nest pas utilis. Par contre, si nous crons un index composite sur le champ Email et sur le champ Noclient qui est la cl primaire et qui nest donc pas nullable , lindex est bien utilis avec le prdicat
Email Is Null.
Create index IS_CLIENTS_EMAIL_NOCLIENT on Clients(email,NoClient); select * from clients where email is null;

Figure5.4b Plan d'excution d'une requte IS NULL utilisant un index.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

97

MS SQL Server et MySQL


Aussi bien sous SQL Server que sous MySQL, le comportement des valeurs nulles lors de l'utilisation des index n'a rien de particulier. La valeur nulle est considre comme une valeur comme une autre et les index sont bien utiliss sur les prdicats IS NULL.

Colonnes incluses

Nous avons vu que si loptimiseur trouve toutes les donnes dans lindex, il peut dcider de ne pas accder la table. Ce comportement peut tre exploit pour amliorer les performances en incluant dans des index les donnes que vous souhaitez rcuprer, on parle alors dindex "couvrant". Par exemple, si vous souhaitez souvent rcuprer la liste des noms des clients dun pays, vous pouvez crer un index sur ces colonnes, en mettant imprativement en premier celles qui servent de critre et en second celles qui sont les colonnes incluses.
create index IS_CLIENTS_PAYSNOM on CLIENTS (PAYS, NOM); select nom from clients t where pays='Cameroun';

On constate dans le plan dexcution de la Figure5.4c que seul lindex est utilis. Cela conomise laccs la table quaurait ncessit un index sur la colonne Pays seule.
Figure5.4c Plan d'excution d'une requte utilisant un index incluant toutes les colonnes.

98

tude et optimisation desrequtes

Axe 2

MS SQL Server
Sous SQL Server, cette approche est intgre dans la syntaxe l'aide du mot cl INCLUDE qui permet d'ajouter des champs l'index sans qu'ils soient inclus dans l'arbre ni comme cl de tri mais seulement dans les feuilles. create index IS_CLIENTS_PAYSNOM on CLIENTS (PAYS) INCLUDE(nom); On constate la nuance par le fait que, sous Oracle, le rsultat apparat tri par nom puisqu'il s'agit d'un parcours de l'index qui est tri sur Pays et Nom alors qu'avec la syntaxe INCLUDE le rsultat n'est pas tri par Nom bien que, l aussi, seul l'index soit parcouru. La diffrence est que la cl de tri de l'index sous SQL Server est seulement le champ Pays, le champ Nom n'est pas stock dans un ordre particulier.

Le facteur de foisonnement

Le facteur de foisonnement (Clustering Factor) tablit le nombre de liens quil y a entre lensemble des feuilles de lindex et les blocs dans le tas. Il permet destimer si le fait que plusieurs valeurs se trouvent dans une mme feuille dindex ncessitera plutt peu de lecture de blocs diffrents dans le tas ou plutt beaucoup. Les donnes relatives au facteur de foisonnement sont disponibles dans la mtabase. On y accde par la requte suivante.
select t.INDEX_NAME,t.LEAF_BLOCKS,t.DISTINCT_KEYS,t.CLUSTERING_FACTOR from sys.user_ind_statistics t where index_name like '%CLIENT%'; INDEX_NAME LEAF_BLOCKS ------------------------------ ----------PK_CLIENTS 94 IS_CLIENTS_VILLE 130 DISTINCT_KEYS CLUSTERING_FACTOR --------------- -----------------45000 759 1096 43479

Clustering_Factor/Leaf_Blocks donne le nombre de liens quil y a en moyenne entre une feuille et des blocs de donnes dans le tas: un ratio infrieur ou gal 3 est excellent. Par contre, lorsque Clustering_Factor tend vers le nombre denregistrements, alors le Clustering Factor est considr comme mauvais. Prenons deux cas pour illustrer le facteur de foisonnement:

Premier cas. Lindex de cl primaire sur la colonne Nocmd de la table des commandes cmd. Si on suppose que les numros de commandes sont crs squentiellement, de faon ordonne et jamais effacs, le tas sera globalement dans le mme ordre que lindex. Si lindex retourne plusieurs RowID depuis un mme bloc (ce qui est caractristique dun prdicat sur une partie de cl ou sur un inter-

Chapitre 5

Techniques doptimisation standard au niveau base de donnes

99

valle), alors il est probable que ces RowID dsignent le mme bloc ou peu de blocs diffrents dans le tas (puisque, gnralement, il y aura plus de blocs dans le tas que de blocs dindex). Dans ce cas, le facteur de foisonnement sera bon. Second cas. Un index sur la colonne Ville dans la table des clients. Si on suppose que les clients nagissent pas de faon concerte ou dirige, alors ils seront mis dans le tas dans lordre suivant lequel ils ont pass leur premire commande mais ils seront normalement dans des villes diffrentes. Donc, le fait de rechercher tous les clients situs "Toulouse" retournera, depuis une ou plusieurs pages conscutives de lindex, des RowID qui dsigneront des blocs qui seront probablement sans aucun point commun. Dans ce cas, le facteur de foisonnement sera mauvais. Un bon facteur de foisonnement permettra davoir de meilleures performances lors dune opration Index Range Scan puisque, pour chaque feuille dindex, il y aura peu de blocs de donnes charger depuis le tas. Pour les autres types daccs, limpact sera gnralement faible. Un mauvais facteur de foisonnement aura pour effet de considrer un Index Range Scan moins intressant (voir lAnnexeB, sectionB.4, pour un exemple dimpact). Il nest pas trop possible dinfluer sur le facteur de foisonnement.
5.2.2 Index sur fonction

Comme nous lavons vu prcdemment, lexcution de fonctions sur des colonnes indexes a pour consquence que les index ne sont pas utiliss sur ces colonnes, ce qui peut tre pnalisant. Par exemple, la requte suivante ignore lindex qui est prsent sur la colonne Nom.
create index IS_CLIENTS_NOM on CLIENTS(NOM); Select * from clients Where Upper(Nom)='NEVILLE';

Pour pallier ce problme, il est possible de crer des index sur fonction. Il sagit dindex B*Tree classiques sauf que leur cl nest pas la valeur de la colonne indexe mais le rsultat de la fonction sur la valeur de la cl. Dans notre exemple, lindex contiendra donc Upper(Nom) et non pas Nom.
create index IS_CLIENTS_UPPER_NOM on CLIENTS(Upper(NOM)); Select * from clients Where Upper(Nom)='NEVILLE';

Malgr leur nom, les index sur fonction sappliquent aussi des expressions. Ainsi, il est possible de dfinir un index sur une expression quelconque, condition quelle soit dterministe et rptable (il est interdit dutiliser SYSDATE ou DBMS_RANDOM).

100

tude et optimisation desrequtes

Axe 2

Lexemple ci-aprs cre un index sur une expression qui est utilise par la requte suivante malgr le fait que les oprandes ont t permuts.
create index IS_CLIENTS_NOCLIENT10 on CLIENTS(NoClient+10); Select * from clients Where 10+NoClient=14813

Oracle 11g introduit la notion de colonne virtuelle. Ce sont des colonnes calcules dont le rsultat nest pas stock. Elles peuvent tre indexes et auront alors le mme fonctionnement quun index sur fonction. Dans lexemple suivant, nous crons une colonne virtuelle et nous lindexons: quon linterroge ou quon fasse une requte sur sa dfinition, dans les deux cas lindex est utilis.
alter table clients add upper_nom varchar2(50) as (upper(nom)); create index is_clients_upper_nom on clients(upper_nom); select * from clients t where upper(nom)='GORE'; select * from clients t where upper_nom ='GORE';

MySQL
MySQL ne propose ni la notion d'index sur fonction, ni la notion de colonne virtuelle.

MS SQL Server
SQL Server propose la fois la notion d'index sur fonction et la notion de colonne virtuelle. Il est possible, pour cette dernire, de la dfinir "persistante", c'est--dire stocke dans la table et non pas calcule la vole.

5.2.3

Reverse Index

Ce sont des index B*Tree qui indexent les valeurs miroirs (par exemple, le nom "Jones" devient "senoJ"). La syntaxe est identique, il faut juste spcifier le mot cl REVERSE la fin de linstruction:
Create index <Nom_Index> on <NomTable>(<col1>[,<col2>,]) REVERSE

Le but de ce type dindex est dviter que deux valeurs qui se suivent dans leur ordre naturel se retrouvent dans la mme feuille. Lobjectif est ici de sorganiser pour avoir un mauvais facteur de foisonnement. Dans quel intrt? Imaginez une table dont la cl est un numro squentiel et quil y ait de nombreuses insertions en parallle. On se retrouve alors avec plusieurs requtes qui vont vouloir mettre jour la mme feuille dindex. Or, cette opration ne peut pas tre faite par deux requtes simultanment: cela aurait pour effet de bloquer chacune delles le temps que la prcdente ait termin la mise jour de la feuille dindex. Avec un

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 101

index reverse, elles vont mettre jour des feuilles dindex diffrentes et ainsi elles ne se gneront pas. Cela permet donc de rduire la contention daccs en criture des feuilles dindex, ce qui sera intressant sur des requtes parallles, particulirement en environnement Oracle RAC. Cependant, ce type dindex montre des limites car il nest utilisable que sur des conditions de type galit (=), ce qui signifie quil ne fonctionnera pas pour des oprations Index Range Scan. De plus, contrairement une rumeur rpandue, ce type dindex ne fonctionne PAS sur les requtes de type Nom like %nes, cest--dire avec un masque de LIKE commenant par% et ayant une fin fixe.
5.2.4 Index bitmap

Les index bitmap sont adapts la manipulation de colonnes avec peu de valeurs distinctes. Ils ne sont utilisables que pour des prdicats dgalit, mais Oracle arrive, dans certains cas, convertir des intervalles par un ensemble dgalit, rendant ainsi ces index oprants sur des intervalles et mme sur des jointures. Les index bitmap sont des masques de bits pour les valeurs distinctes des colonnes indexes : des ET et OU binaires permettent de faire des tests dgalit. Nous lillustrons ci-aprs avec la table emp du schma scott des bases exemples dOracle. On voit que la colonne Job peut prendre cinq valeurs possibles (voir Figure5.5a). Lindex bitmap code ces valeurs par cinq masques de bits (voir Figure5.5b). Chaque bit spcifie par un1 que la ligne contient la valeur ou par un0 quelle ne la contient pas. Si nous cherchons slectionner les personnes ayant un job de PRESIDENT ou de COMPTABLE, il suffit de faire un OU binaire entre les deux masques pour connatre les lignes qui ont une de ces valeurs (voir Figure5.5b). Lintrt le plus significatif des index bitmap est quon peut en combiner plusieurs dans un mme accs une table. Pour cela, il suffira dappliquer des oprations logiques sur les diffrents masques de chaque index comme sil sagissait du mme index bitmap. Les index B*Tree ne sont pas conus pour tre combins; ils ne peuvent donc pas ltre efficacement. En revanche, sil y a plusieurs index bitmap couvrant les prdicats dune requte, ils seront combins. En fait, les index bitmap ne sont pas stocks comme cest prsent la Figure5.5b car ils sont compresss. La technique de compression utilise est sensible au foisonnement. Ainsi, si les lignes qui se suivent ont souvent la mme valeur, la compression sera bien meilleure que si chaque ligne a une valeur diffrente de la prcdente. Le taux de compression aura un impact sur lespace requis pour stocker lindex bitmap et donc sur le nombre de Consistent Gets. Il faut avoir en tte que, si les

102

tude et optimisation desrequtes

Axe 2

valeurs distinctes sont distribues sur lensemble de la table plutt que regroupes par paquets, lindex occupe plus despace.
COMPTABLE

Figure5.5a
N ligne

EMPNO 14347 14484 14621 14758 14895 15032 15169 15306 15443 15580 15717 15854 15991 16128

ENAME DUPOND MICHEL LEROY DURAND MEUNIER MARTIN DUPONT LECLERC NEUVILLE DUJARDIN BERTHIER GUY RENAUD LAVAUR

JOB COMPTABLE VENDEUR VENDEUR MANAGER VENDEUR MANAGER MANAGER INGENIEUR PRESIDENT VENDEUR COMPTABLE COMPTABLE INGENIEUR COMPTABLE

1 2 3 4 5 6 7 8 9 10 11 12 13 14

1 0 0 0 0 0 0 0 0 0 1 1 0 1

VENDEUR

Reprsentation logique d'un index bitmap.

0 1 1 0 1 0 0 0 0 1 0 0 0 0

0 0 0 0 0 0 0 0 1 0 0 0 0 0

0 0 0 1 0 1 1 0 0 0 0 0 0 0

Figure5.5b Reprsentation interne d'un index bitmap.

N ligne COMPTABLE VENDEUR PRESIDENT MANAGER INGENIEUR COMPTABLE OU PRESIDENT

1 1 0 0 0 0

2 0 1 0 0 0

3 0 1 0 0 0

4 0 0 0 1 0

5 0 1 0 0 0

6 0 0 0 1 0

7 0 0 0 1 0

8 0 0 0 0 1

9 0 0 1 0 0

10 0 1 0 0 0

11 1 0 0 0 0

12 1 0 0 0 0

13 0 0 0 0 1

INGENIEUR 0 0 0 0 0 0 0 1 0 0 0 0 1 0

PRESIDENT

MANAGER

14 1 0 0 0 0

Index bitmap et oprations LMD

Il nest pas recommand dutiliser les index bitmap sur des tables trs mouvementes par des sessions concurrentes Cela peut poser des problmes de verrouillage cause de la structure de stockage interne des RowID, laquelle permet dconomiser de lespace. Ce sont des index plutt orients datawarehouse mais qui restent cependant tout fait utilisables dans des environnements OLTP modrs.
Index bitmap et valeurs nulles

Les index bitmap grent mieux les valeurs nulles que les index B*Tree puisque les valeurs NULL sont considres comme des valeurs distinctes au mme titre que les autres.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 103

Mise en uvre

La syntaxe de cration dun index bitmap est trs proche de celle dun index B*Tree, il faut juste ajouter le mot cl bitmap. Ici aussi, il est possible de crer des index sur fonction avec les index bitmap.
create bitmap index <Nom_Index> on <NomTable>(<col1>[,<col2>,]);

Les index bitmap prsentent lintrt dtre adapts lindexation de colonnes ayant peu de valeurs distinctes. Cependant, un index bitmap employ sur une seule colonne de faible slectivit ne sera pas beaucoup plus efficace quun index B*Tree. Lavantage majeur des index bitmap apparat lors de la combinaison de conditions sur des colonnes ayant chacune une faible slectivit mais qui, ensemble, auront une forte slectivit. Sinon, on retrouve le problme des index B*Tree o le cot des allers-retours entre lindex et le tas dpasse le gain apport par lindex. Les index bitmap sont rputs pour tre adapts des colonnes ayant relativement peu de valeurs distinctes. Cependant, les rsultats des tests ci-aprs montrent que, mme avec 20millions de valeurs distinctes, ils ont de bonnes performances. Nanmoins, ils occupent, dans ce cas, plus despace que des index B*Tree, alors que cest gnralement le contraire. On constate que, sil y a peu de valeurs distinctes, ils ont des tailles trs faibles par rapport aux index B*Tree, ce qui rendra leur manipulation dautant plus efficace. Par contre, lorsque le nombre de valeurs distinctes augmente ( partir de un million de valeurs), on saperoit que la taille de lindex bitmap explose. La taille dun index B*Tree est constante mais plus importante que celle des index bitmap dans de nombreux cas puisque chacune de ses entres contient la cl plus le RowID, contrairement aux index bitmap qui ont une technique de stockage optimise. Ci-aprs, on lit quelques rsultats de tests de performance montrant le bon comportement des index bitmap sur une table de 20 millions denregistrements avec des colonnes indexes ayant de 2 20millions de valeurs distinctes. On y trouve le temps ncessaire pour effectuer le calcul dune moyenne sur une colonne de la table en fonction dun critre sur une colonne indexe ayant plus ou moins de valeurs distinctes. Le test est fait avec un index bitmap, un index B*Tree et sans aucun index. Ces tests ont t raliss avec des donnes ayant un trs bon facteur de foisonnement, ce qui amliore un peu les choses, spcialement sur les tests ayant peu de valeurs distinctes.

104

tude et optimisation desrequtes

Axe 2

Figure5.6a volution de la taille des index bitmap et B*Tree en fonction du nombre de valeurs distinctes (chelle logarithmique).
Mo 1 000

Nb de valeurs distinctes Taille Bitmap 2 20 200 2 000 20 000 200 000 2 000 000 20 000 000 4 Mo 4 Mo 5 Mo 5 Mo 5 Mo 10 Mo 63 Mo 576 Mo

Taille B*Tree 376 Mo 376 Mo 376 Mo 376 Mo 376 Mo 376 Mo 376 Mo 376 Mo

100

10

1
0 2 20 0 0 0 0 0 20 00 00 00 00 2 20 0 0 0 20 20 00 0 00 0 00 00 0

20

Taille Index B*Tree

Taille Index Bitmap

Figure5.6b Temps de rponse en fonction du nombre de valeurs distinctes.

Nb de valeurs distinctes Temps Bitmap Temps B*Tree Temps Sans Index 2 20 200 2 000 20 000 200 000 2 000 000 20 000 000
secondes 80 70 60 50 40 30 20 10 0
0 2 20 0 00 0 00 0 00 0 2 20 0 0 00 0 20

20,500 s 0,719 s 0,078 s 0,015 s 0,015 s 0,015 s 0,015 s 0,015 s

67,000 s 0,484 s 0,062 s 0,016 s 0,015 s 0,015 s 0,015 s 0,015 s

00

23,125 s 23,125 s 23,125 s 23,125 s 23,125 s 23,125 s 23,125 s 23,125 s

20

Temps B*Tree

Temps Bitmap

Temps Sans Index

00

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 105

Figure5.6c Nombre de Consistent Gets en fonction du nombre de valeurs distinctes.

Nb de valeurs distinctes 2 20 200 2 000 20 000 200 000 2 000 000 20 000 000
Consistent Gets 160 000 140 000 120 000 100 000 80 000 60 000 40 000 20 000 0
0 2

Consistent Gets Bitmap 73 285 6 918 656 63 9 4 4 3

Consistent Consistent Gets Gets B*Tree Sans Index 96 650 9 266 890 90 90 83 83 3 144 123 144 123 144 123 144 123 144 123 144 123 144 123 144 123

20

20

00

00

00

00

20

20

00

Gets B*Tree

Gets Bitmap

Gets Sans Index

valuation

valuons les diffrentes solutions pour filtrer plusieurs colonnes de faible cardinalit, sur une table de 2606477enregistrements avec des conditions sur la colonne Nolivre ayant 2 972 valeurs distinctes et la colonne Remise ayant 3 valeurs distinctes. Nous allons comparer les diffrentes solutions avec la requte suivante:
select * from cmd_lignes where nolivre=6262 and remise=7

Sans aucun index, il faut parcourir toute la table do de nombreux Consistent Gets (voir Figure5.7). Avec 2 index B*Tree, le SGBDR convertit les rsultats des Range Scan en index bitmap afin de les combiner (voir Figure5.8).

20

00

00

106

tude et optimisation desrequtes

Axe 2

Figure5.7 Sans aucun index.

Figure5.8 Avec deux index B*Tree.

On voit donc que, dans certains cas, plusieurs B*Tree peuvent tre utiliss lors dun mme accs une table, mais le cot li la conversion en index bitmap est lev. En fait, dans cet exemple en particulier, loptimiseur avait choisi de nutiliser que lindex sur Nolivre. Nous avons forc ce comportement afin de vous le prsenter.
create index IS_cmd_lignes_Livre on cmd_lignes(nolivre); create index IS_cmd_lignes_Remise on cmd_lignes(Remise);

Si les index B*Tree ne sont pas conus pour tre combins, les index composites grent parfaitement les conditions sur deux colonnes. Nous obtenons ainsi un bon rsultat (voir Figure5.9).
create index IS_CMD_LIGNES_LIVREREMISE on CMD_LIGNES (nolivre, remise)

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 107

Lutilisation des index composites est trs efficaces lorsque les conditions des requtes sappliquent exactement aux colonnes de lindex. Si les conditions peuvent varier sur un ensemble de colonnes (par exemple une requte avec des conditions sur Col1, Col2 et Col5, une deuxime requte sur Col2, Col3 et Col4, une troisime requte sur Col1, Col3 et Col6), il faudrait crer autant dindex composites que de combinaisons possibles entre les colonnes ce qui risquerait doccuper pas mal despace de stockage et dimpacter les mises jour de la table.
Figure5.9 Avec index B*Tree composite.

Avec les deux index bitmap suivants:


create bitmap index IS_cmd_lignes_Livre on cmd_lignes(nolivre); create bitmap index IS_cmd_lignes_Remise on cmd_lignes(Remise);

Figure5.10 Avec deux index bitmap.

108

tude et optimisation desrequtes

Axe 2

On voit que les deux index bitmap sont naturellement combins (voir Figure5.10). Cette solution est lgrement moins bonne que lindex B*Tree composite de cet exemple mais, suivant les cas, la tendance peut sinverser. Ces deux solutions ont souvent des performances comparables. La solution avec les index bitmap allie performance, faible encombrement et flexibilit des conditions. Au Tableau5.1, nous voyons que les index bitmap sont plus petits.
Tableau5.1: Taille des diffrents index

Type index Index bitmap Index B*Tree Index B*Tree composite

Taille index NoLivre 10Mo 44Mo 51Mo

Taille index Remise 0.88Mo 39Mo

5.2.5

Bitmap Join Index

Les Bitmap Join Index permettent de crer des index bitmap bass sur les valeurs dune autre table avec laquelle on prvoit de faire une jointure. Dans lexemple ci-aprs, nous crons un index dans la table cmd_lignes portant sur la colonne Collection de la table livres. Ainsi, si nous effectuons une requte sur la table cmd_ lignes avec comme condition la colonne Collection, le SGBDR naura pas besoin de faire la jointure avec la table livres, ce qui apportera un gain significatif. Ilfaudra cependant continuer crire cette jointure dans la requte:
create bitmap index is_cmd_lignes_collect on cmd_lignes(l.collection) from cmd_lignes cl,livres l where cl.nolivre=l.nolivre;

Voici un exemple de requte tirant parti du Bitmap Join Index:


select sum(quantite) from cmd_lignes cl,livres l where cl.nolivre=l.nolivre and l.collection='Best-sellers';

Ce type dindex est particulirement intressant si vous avez besoin de faire des jointures uniquement pour appliquer des conditions par galit. Dans ce cas, il ny aura plus besoin de faire la jointure, ce qui apportera un gain significatif. Par contre, si la jointure reste ncessaire pour appliquer des conditions ou afficher les autres champs, lindex sera moins intressant mais il pourra cependant toujours prsenter un intrt, car il rduira la taille de lensemble joindre.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 109

Il faut bien garder lesprit quun Bitmap Join Index est avant tout un index bitmap, cest--dire quil est conu pour les tests dgalit, quil est surtout recommand pour un faible nombre de valeurs distinctes et quil nest pas adapt aux tables soumises beaucoup de LMD concurrents.
Mise en uvre

La syntaxe dun Bitmap Join Index est la suivante:


create bitmap index <Nom_Index> on <NomTable>(<col1>[,<col2>,]) from <NomTable>,<NomTableJointe> Where <JointureEntreLesTables> ;

valuation

Nous allons valuer les performances de cet objet avec la requte suivante:
select sum(quantite) from cmd_lignes cl,livres l where cl.nolivre=l.nolivre and cl.remise=7 and l.collection='Programmeur'

Dans cette premire trace dexcution, il y a un index bitmap sur la colonne Remise mais il nest pas utilis car une opration table access full est requise pour la jointure.
Figure5.11 Trace d'excution sans Bitmap Join Index.

Dans la deuxime trace dexcution (voir Figure 5.12), nous avons plac un Bitmap Join Index sur le champ Collection (voir exemple prcdent). Nous voyons que loptimiseur nestime plus ncessaire de faire une jointure avec la table livre pour rpondre cette requte (alors que celle-ci est prsente dans la requte). En consquence, les deux index bitmap sont combins ce qui est particulirement efficace. Les Consistent Gets sont diviss par 180 et le temps dexcution par10.

110

tude et optimisation desrequtes

Axe 2

Figure5.12 Trace d'excution avec un Bitmap Join Index.

Dans la troisime trace dexcution (voir Figure 5.13), nous avons plac des index bitmap sur Remise et Nolivre mais supprim le Bitmap Join Index. Nous constatons une jointure par boucle imbrique sur lindex bitmap de la colonne Nolivre qui est combine au filtrage bitmap sur la colonne remise. Les performances sont moindres quavec le Bitmap Join Index mais cependant acceptables. Si lindex sur la colonne Nolivre avait t de type B*Tree, le plan aurait t quasiment le mme car le rsultat du Range Scan de lindex B*Tree aurait t converti en bitmap.
Figure5.13 Trace d'excution sans Bitmap Join Index mais avec des index bitmap sur NoLivre et Remise.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 111

MS SQL Server et MySQL


Ni SQL Server, ni MySQL ne proposent d'index bitmap ou de Bitmap Join Index.

5.2.6

Full Text Index

En SQL de base, pour chercher un texte dans une chane de caractres, on crit quelque chose comme ceci:
select count(*) from texteslivres where texte like '%voyage%';

Cest simple comprendre mais ce nest pas trs efficace sur des textes un peu importants. De plus, si le texte est dans un champ de type CLOB, les performances scroulent cause des accs au segment LOB qui est spar du tas. Le principal problme de cette requte est quelle ne peut utiliser aucun index B*Tree car la prsence de like %... est un cas disqualifiant pour lusage des index. Nous allons regarder comment optimiser ce type de requte, mais nous avons besoin dabord dune base de donnes avec un peu de texte. Pour cela, nous nous rendons sur le site http://www.livrespourtous.com et nous rcuprons quelques livres de Victor Hugo et dmile Zola, nous dcoupons approximativement les pages et nous les chargeons dans la table ci-aprs. Afin daugmenter un peu le volume, nous dupliquons ces donnes en cinq exemplaires, ce qui nous permet davoir une table de 17325enregistrements pour une taille de 40Mo. Cette base est disponible sur le site de lauteur, ladresse http://www.altidev.com/livres.php.
create table TextesLivres( ID NUMBER, Auteur varchar2(100), Titre varchar2(100), SousTitre varchar2(100), TEXTE CLOB, constraint PK_TextesLivres primary key (ID) ); insert into texteslivres select id+10000, auteur, titre, texte from texteslivres where id <5000 order by 1; insert into texteslivres select id+20000, auteur, titre, texte from texteslivres where id <5000 order by 1; insert into texteslivres select id+30000, auteur, titre, Quater', texte from texteslivres where id <5000 order insert into texteslivres select id+40000, auteur, titre, quinquies', texte from texteslivres where id <5000 order

soustitre||' Bis', soustitre||' Ter', soustitre||' by 1; soustitre||' by 1;

112

tude et optimisation desrequtes

Axe 2

La requte suivante a un temps dexcution de 2,75 secondes et ncessite 5144Consistent Gets.


select count(*) from texteslivres where texte like '%voyage%';

La variante de cette requte utilisant la fonction UPPER a un temps dexcution de 2,92secondes et ncessite 22999Consistent Gets.
select count(*) from texteslivres where upper(texte) like '%VOYAGE%'

Si les textes sont suprieurs 4000caractres, ils sont stocks dans un segment spar (voir la section5.3.1 pour plus de dtails), ce qui va encore plus pnaliser ce genre de requte. Dans notre cas, seulement 0,4% des enregistrements dpassent cette limite. Mais si nous modifions les paramtres de la table avec la clause DISABLE STORAGE IN ROW, qui permet de forcer le stockage systmatique dans un segment spar, alors notre requte a un temps dexcution de 17secondes et ncessite 111632Consistent Gets. Maintenant que nous avons mis en vidence que loprateur LIKE nest pas une solution trs performante pour effectuer des recherches dans des champs texte, voyons les solutions possibles. Oracle met notre disposition des outils qui sont adapts ces problmatiques au moyen dindex spcifiques de domaine. Je vous conseille de consulter le document Oracle Text Application Developers Guide dans la documentation Oracle pour avoir des informations dtailles. Nous tudierons ici les lments cls qui permettent doptimiser les requtes de type Full Text Search de plus en plus prises avec lavnement du Web et de Google. Oracle Text met disposition des index adapts aux recherches de textes. Ils sont capables de travailler sur des champs texte mais aussi sur des champs de type BLOB contenant des fichiers bureautiques. La phase dindexation utilise un filtre qui convertit les documents (word, pdf, etc.) en texte et un analyseur lexical (lexer) qui fait une analyse lexicale du texte afin den extraire les mots (ainsi, les recherches se font au niveau des mots et non pas sur des morceaux de chanes contrairement aux recherches laide du prdicat like %chane%). Lanalyseur lexical peut aussi convertir les caractres en majuscules (par dfaut) et les signes diacritiques (caractres accentus, trma, etc.) en leurs caractres de base afin de faire correspondre les recherches avec ou sans accents (dsactiv par dfaut). Plusieurs types dindex sont notre disposition, chacun orient vers un usageparticulier:
CONTeXT.

Adapt aux recherches de mots dans des grands champs texte ou des documents. Ce type dindex extrait tous les mots des documents, les compte et les associe aux enregistrements concerns. Les mots ne sont donc pas rpts, ce

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 113

qui permet davoir frquemment un index plus petit que le texte original. Ce type dindex doit, par dfaut, tre synchronis manuellement.
CTXCAT.

Adapt pour indexer de petits textes en les combinant avec des champs structurs afin de faire des recherches combines plus efficaces. Il occupe pas mal de place et peut dpasser largement la taille du texte initial. Il nest donc pas adapt lindexation de grands textes. Ce type dindex est synchronis automatiquement.

CTXRULe.

Permet de classifier les documents suivant leur contenu partir de loprateur MATCHES. CTXXpATH. Adapt lindexation des documents XML. Pour des recherches Full Text sur des champs volumineux comme dans notre exemple, il est donc recommand dutiliser un index de type CONTEXT.
Mise en uvre d'un index CONTEXT

La syntaxe de base permettant de crer un index Full Text de type suivante:

CONTEXT

est la

create index <NomIndex> on <NomTable>(<colonnes>) indextype is CTXSYS.CONTEXT;

Ci-aprs, vous voyez un exemple de cration dun index o une conversion des signes diacritiques en caractres de base est spcifie. La premire tape consiste crer des prfrences pour le lexer. Elle est ncessaire une seule fois pour lensemble des index partageant les mmes prfrences de lexer. La seconde tape vise la cration de lindex lui-mme, en spcifiant le type CONTEXT et les ventuels paramtres.
begin ctx_ddl.create_preference('mylex', 'BASIC_LEXER'); ctx_ddl.set_attribute ( 'mylex', 'base_letter', 'YES'); end; create index IS_FT_TEXTESLIVRES on TEXTESLIVRES(texte) indextype is CTXSYS.CONTEXT parameters ( 'LEXER mylex' );

la suite de la cration de lindex, les tables suivantes sont cres : dr$is_ft_ texteslivres$i, dr$is_ft_texteslivres$k, dr$is_ft_texteslivres$n, dr$is_ ft_texteslivres$r. Dans lexemple, elles occupent 20Mo alors que notre table occupe 40Mo. Si nous regardons de plus prs la table dr$is_ft_texteslivres$i, nous constatons quelle contient chaque mot converti en majuscules et sans signes diacritiques, ainsi que le nombre doccurrences de chaque mot. Maintenant que les donnes sont indexes, nous pouvons faire des recherches laide de loprateur CONTAINS (cet oprateur nest oprationnel que si un index

114

tude et optimisation desrequtes

Axe 2

textuel est prsent). Comme nous le voyons dans lexemple suivant, nous avons notre disposition la fonction SCORE qui donne un score de pertinence de la rponse.
SELECT SCORE(1) score,id FROM texteslivres WHERE CONTAINS(texte, 'voyage', 1) > 0 ORDER BY SCORE(1) DESC;

Cette requte ne retourne plus que 310 enregistrements, alors que la prcdente, implmente avec un prdicat LIKE, en annonait 680. Cela vient juste du fait que la version avec like %voyage% considre aussi les valeurs suivantes: voyageaient, voyageait, voyageant, voyager, voyagera, voyages, voyageur, voyageurs, voyageuse, voyageuses alors que loprateur CONTAINS lui travaille sur les mots et fait donc la diffrence entre les mots voyage et voyager. Pour chercher plusieurs mots, il ne faut pas utiliser un oprateur AND dans la clause WHERE mais la syntaxe & de loprateur CONTAINS comme dans lexemple ci-aprs, qui recherche les textes contenant les mots "voyage" et "soleil".
SELECT count(*) FROM texteslivres WHERE CONTAINS(texte, 'voyage & soleil', 1) > 0

Loprateur CONTAINS gre lui tout seul tout un langage de requte texte. Consultez la documentation de rfrence Oracle Text pour avoir plus de dtails sur les possibilits de cet oprateur. On peut, par exemple, faire des recherches floues, des combinaisons, utiliser des thesaurus, des proximits de mots, etc. La requte ci-aprs trouvera les textes avec les mots proches de "voyage" tels que "voyageur" et exclura le mot "voyage" avec loprateur~.
SELECT * FROM texteslivres WHERE CONTAINS(texte, 'fuzzy(voyage) ~voyage', 1) > 0

Si on compare la solution avec loprateur LIKE prcdemment teste, la requte suivante prend 0,172seconde et ncessite 1165Consistent Gets.
SELECT count(*) FROM texteslivres WHERE CONTAINS(texte, 'voyage', 1) > 0

Certes, cest beaucoup pour un index mais cela reste en trs net progrs puisque nous avons divis le temps dexcution par 16 par rapport la solution initiale et mme par 100 par rapport la version qui utilisait un stockage dans un segment LOB spar. Bien que les index de type CONTEXT ne soient pas synchroniss automatiquement avec les donnes, leur mise jour est incrmentale. Il faut utiliser la commande suivante pour excuter une synchronisation de lindex avec les donnes:
EXEC CTX_DDL.SYNC_INDEX('IS_FT_TEXTESLIVRES');

Il est cependant possible de spcifier dans le CREATE sement automatique lors de la cration de lindex:

INDEX des clauses de rafrachis-

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 115

SYNC(MANUAL |EVERY "interval-string" |ON COMMIT)

Au fur et mesure que lindex grandit avec les synchronisations, il se fragmente, on doit donc rgulirement loptimiser. Durant cette opration, dans sa version rapide (Fast), les entres dindex associes des enregistrements qui ont t supprims ou qui ne sont plus dans lenregistrement ne sont pas automatiquement effaces. Ilfaut, pour traiter ces cas-l, effectuer une optimisation complte afin de les purger (remplacer FAST par FULL ci-aprs).
EXEC CTX_DDL.OPTIMIZE_INDEX('IS_FT_TEXTESLIVRES','FAST');

Mise en uvre d'un index CTXCAT

Les index CTXCAT sont adapts lexcution de requtes combinant une recherche Full Text avec des critres sur les autres colonnes de lenregistrement. Ce type de requte est possible avec les index CONTEXT: il suffit de mettre les deux prdicats dans la requte. Cependant, cette solution ncessite de parcourir dabord lindex CONTEXT puis daller vrifier les autres prdicats pour chaque enregistrement. Cela risque dtre peu efficace si les autres prdicats portant sur les champs de la table sont trs slectifs. Lindex CTXCAT, comme lindex CONTEXT isole les mots. En plus, pour chaque enregistrement, il stocke aussi les valeurs des autres champs qui sont mentionns lors de sa cration pour pouvoir faire des recherches combines. Si le rsultat est assez efficace, lespace occup est particulirement important puisque chaque mot est stock avec les valeurs des autres champs de lindex. Comme nous lavons dit prcdemment, ces index ne sont pas adapts lindexation de textes volumineux. Nous allons donc prendre comme exemple le champ Adresse de la table clients de notre base exemple et le combiner au champ Pays, puis comparer les performances sur le domaine des recherches combines. cette fin, nous crons un index de type CTXCAT intgrant la colonne Pays de la table clients:
EXEC CTX_DDL.CREATE_INDEX_SET('ISET_IS_CLIENT_ADRESSE_PAYS'); EXEC CTX_DDL.ADD_INDEX('ISET_IS_CLIENT_ADRESSE_PAYS','PAYS'); CREATE INDEX IS_CLIENT_ADRESSE_PAYS ON CLIENTS(Adresse1) INDEXTYPE IS CTXSYS.CTXCAT PARAMETERS ('index set ISET_IS_CLIENT_ADRESSE_PAYS');

La requte suivante sexcute en 0,015seconde et ncessite 4Consistent Gets:


select * from clients t where CATSEARCH(adresse1,'FOREST', 'pays = ''Japan''')> 0;

116

tude et optimisation desrequtes

Axe 2

alors que lquivalent, avec un index de type CONTEXT et loprateur CONTAINS combin une clause WHERE, sexcute en 0,016seconde et ncessite 130Consistent Gets. Lquivalent avec un prdicat LIKE sexcute en 0,016seconde et ncessite 628Consistent Gets. Le temps dexcution nest pas trs significatif tant donn le faible volume, mais le nombre de Consistent Gets est parlant: entre la solution la plus lente et la plus rapide, il y a un ratio de 150. Cependant, le prix payer pour lindex CTXCAT est de 18Mo alors que la table occupe seulement 5Mo. Le cot de lindex CONTEXT est lui de 1,3Mo. Ci-dessous les instructions permettant deffectuer le test utilisant un index CONTEXT
CREATE INDEX IS_FT_CLIENTS_ADRESSE1 ON CLIENTS(ADRESSE1) INDEXTYPE IS CTXSYS. CONTEXT parameters ( 'LEXER mylex' ); select * from clients where CONTAINS(adresse1, 'FOREST', 1) > 0 and pays='Japan';

Ci-dessous les instructions permettant deffectuer le test nutilisant aucun index:


select * from clients where upper(adresse1) like '%FOREST%' and pays='Japan'

MS SQL Server
Sous SQL Server, la fonctionnalit de recherche Full Text est dlgue des services externes la base de donnes (Msftesql.exe et Msftefd.exe), de ce fait, les index Full Text ne sont pas dans la base de donnes. La fonctionnalit doit tre active pour chaque base de donnes soit dans SQL Server Management Studio, dans l'onglet Fichier des proprits de la base de donnes, soit avec l'instruction suivante: EXEC sp_fulltext_database @action = 'enable' Il faut ensuite crer un catalogue, qui pourra tre utilis pour plusieurs tables. Cependant, pour indexer de gros volumes, il sera pertinent de crer des catalogues indpendants pour chaque table. L'instruction Create Fulltext Catalog permet de crer le catalogue en spcifiant les options de gestion des caractres diacritiques ainsi que l'emplacement des fichiers d'index sur le disque dur: CREATE FULLTEXT CATALOG MonCatalogueFT as default Il ne sera possible de crer qu'un seul index par table qui contiendra l'ensemble des colonnes indexer: Create Fulltext Index on texteslivres (texte) KEY INDEX PK_TextesLivres WITH CHANGE_TRACKING AUTO Create Fulltext Index on <NomDeLaTable>(<Colonnes, >) KEY INDEX <ClePrimaireOuAutreIndexUnique> WITH CHANGE_TRACKING <OptionsDeMiseAJour>

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 117

Ensuite, il est possible de faire des recherches Full Text avec diffrents oprateurs. L'oprateur CONTAINS permet de faire des recherches de termes simples en les combinant ventuellement avec des oprateurs boolens (AND, AND NOT, OR). Il intgre aussi la notion de prfixe "voyage*", les notions d'inflexion FORMSOF ( INFLECTIONAL ,voyage) et de synonymes au moyen d'un thesaurus. select count(*) from texteslivres where CONTAINS(texte, 'voyage') La fonction CONTAINSTABLE est une variante de CONTAINS qui permet de retourner une table deux colonnes contenant la cl de l'index (Key) et le classement par pertinence
(Rank) :

select * from CONTAINSTABLE(texteslivres,texte, 'voyage') L'oprateur FREETEXT permet de faire une recherche analogue CONTAINS en incluant les inflexions et les synonymes mais avec une syntaxe plus simple puisqu'il suffit de spcifier la liste de mots recherchs: select * from texteslivres where FREETEXT(texte, 'voyage train') La fonction FREETEXTTABLE retourne une table comme CONTAINSTABLE mais avec la syntaxe de FREETEXT.

MySQL
MySQL intgre aussi un mcanisme de recherche Full Text mais seul le moteur MyISAM intgre un index spcialis permettant d'avoir de meilleurs rsultats. Ci-aprs, un exemple de cration d'index et de recherche est prsent: Create FULLTEXT index IS_FT_TEXTESLIVRES ON TEXTESLIVRES(texte); SELECT * FROM texteslivres WHERE match(texte) against ('voyage') Les recherches sont faites, par dfaut, en mode langage naturel mais il est possible de travailler en mode boolen. La requte suivante recherche les enregistrements avec le mot "voyage" mais sans le mot "voyageur". Le signe plus (+) exige la prsence du mot, le signe moins () exige son absence, sinon la prsence est optionnelle mais augmente la pertinence. L'oprateur* permet de faire des recherches sur le dbut d'un mot (voyag*), > et < donnent plus ou moins d'importance certains mots, les guillemets servent chercher des correspondances exactes sur des phrases. SELECT * FROM texteslivres WHERE match(texte) against ('+voyage voyages -voyageur' in BOOLEAN mode) Par dfaut, le rsultat est tri par pertinence. Tout comme sous Oracle, il est possible de crer un index sur plusieurs colonnes et d'effectuer une recherche simultanment sur plusieurs colonnes.

118

tude et optimisation desrequtes

Axe 2

5.3

Travail autour des tables

5.3.1 Paramtres de table PCTFree = 0 travers la clause de stockage et le paramtre PCTFREE (valant 10% sil est omis), le SGBDR rserve lors des insertions de donnes PCTFree % despace dans chaque bloc pour agrandir les donnes sans devoir faire de migration de ligne (row migration) lors des UPDATE qui auront peut-tre lieu dans le futur.

Certaines tables contiennent des donnes dont les enregistrements ne grossiront jamais, lespace rserv par loption PCTFREE est donc perdu. De plus, il entranera lusage de PCTFree% blocs supplmentaires pour stocker le mme nombre denregistrements que si le paramtre tait 0%. Cela augmentera donc le nombre de Consistent Gets et rduira les performances dautant. Sur les tables qui ont des lignes qui ne varient pas en taille, il est donc pertinent de spcifier le paramtre PCTFREE 0 dans la clause de stockage.
Create table xxx ( . . . ) PCTFREE 0;

Rpartition des tablespaces

Pour chaque objet, il est possible de dfinir un tablespace spcifique. Si cette clause est omise, cest le tablespace par dfaut de lutilisateur qui est choisi. Il sera donc le mme pour tous les objets qui nont pas spcifi de tablespace. Si vous disposez de plusieurs disques (ou ensembles de disques), vous avez tout intrt dfinir des tablespaces propres chacun des disques. Ainsi, vous pourrez rpartir les objets qui travaillent simultanment et qui causent des Physical Reads sur des disques diffrents et ainsi cumuler les bandes passantes des diffrents disques. Chaque tablespace est compos de datafiles. Ces fichiers peuvent tre rpartis sur diffrents disques, mais il faut penser quon na aucun moyen dinfluer sur la rpartition des objets dans les datafiles. Donc, si vous souhaitez matriser cette rpartition, crez plutt des tablespaces avec des datafiles sur un seul disque ou groupe de disques.
Create table xxx ( . . . ) TABLESPACE NomDuTablespace;

MS SQL Server
Sous SQL Server, la mme logique est applicable, sauf qu'on parlera de filegroup la place de tablespace. De la mme faon, il est possible d'affecter chaque objet un filegroup.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 119

MySQL
Avec le moteur MyISAM, vous pouvez spcifier les options DATA DIRECTORY et INDEX DIRECTORY pour chaque table et ainsi rpartir vos tables sous diffrents disques. Avec le moteur InnoDB, par dfaut, il n'y a qu'un seul tablespace qui peut tre constitu de plusieurs fichiers rpartis sur plusieurs disques mais, de la mme faon que sous Oracle avec les datafiles, vous ne pouvez pas influer sur la rpartition des donnes dans les fichiers. L'option INNODB_FILE_PER_TABLE permet d'avoir un tablespace par table mais elle ne permet pas de les rpartir sur plusieurs volumes.

Compression de table

Cette option permet de compresser les doublons prsents dans les blocs. On devrait dailleurs parler plutt de "dduplication" que de "compression", car ce terme fait penser, tort, lusage dalgorithmes de compression, tels que Lempel-Ziv. Cependant, la dduplication a lavantage dtre mieux adapte lusage dans une base de donnes. Le principe est de compresser les donnes au sein dun bloc. Les donnes identiques du bloc sont rpertories dans un dictionnaire au dbut du bloc. De ce fait, chaque occurrence des donnes contient seulement une rfrence lentre dans le dictionnaire au lieu de la donne. Le dictionnaire est uniquement constitu de valeurs entires: ainsi, les donnes "Navarro Laurent" et "Laurent Navarro" ne seront pas compresses car elles sont, certes, composes de parties identiques mais elles sont des valeurs diffrentes. De fait, la compression sera gnralement inoprante pour compresser des champs de taille importante. La compression sactive avec loption COMPRESS dans la clause de stockage de la table et elle nest disponible que sur les tables organises en tas (pas sur les IOT que nous tudierons un peu plus loin). COMPRESS fait rfrence la compression de base, qui a t introduite dans la version9i sous le nom de DSS table compression. Ce type ne compresse que les donnes insres en direct path (via sql*loader en mode direct path ou avec le hint APPEND. Voir Chapitre 7, section 7.3.9, "Insertion en mode Direct path"). La version11g Release1 a introduit COMPRESS FOR ALL OPERATION, qui a t remplace dans la version11g Release2 par COMPRESS FOR OLTP. Cette option permet dappliquer la compression toutes les oprations; elle est prsent recommande pour un usage en environnement OLTP.

120

tude et optimisation desrequtes

Axe 2

La compression de table introduit quelques restrictions, telles quun nombre de colonnes infrieur 255, et surtout des limites sur la suppression de colonnes. Sur notre table exemple, cmd_lignes, nous obtenons une rduction de lespace de 25%. En termes de performances sur une requte ncessitant un Full Table Scan dune grosse table, ce qui demande donc des Physical Reads, nous constatons un gain de lordre de 30%. En criture, les performances sont assez bonnes aussi, car la surcharge CPU est gnralement compense par la rduction des entres/sorties. Le seul cas qui semble tre plus frquemment dfavorable la compression est lutilisation dUPDATE. Cette technique ne sera donc pas trs adapte des tables qui subissent de trs nombreuses modifications denregistrements. La version11g Release2 a revu compltement la syntaxe des options de compression. Ces changements sont rsums au Tableau5.2.
Create table xxx ( . . . ) COMPRESS;

Tableau5.2: Options de compression des diffrentes versions d'Oracle

Syntaxe 11g Release 2


COMPRESS ou COMPRESS BASIC COMPRESS FOR OLTP COMPRESS FOR QUERY et COMPRESS FOR ARCHIVE

Syntaxe 11g Release 1


COMPRESS ou COMPRESS FOR DIRECT_LOAD OPERATION COMPRESS FOR ALL OPERATION

Syntaxe 10g et 9i
COMPRESS

Non disponible

Nouvelles options11g Release2 ncessitant le moteur Exabyte

MS SQL Server
La version2008, dans ses ditions Entreprise et Dveloppeur, a introduit deux notions de compression: la compression de ligne et la compression de page. La compression de ligne est un mcanisme qui optimise l'espace requis pour le stockage des types de taille fixe. La compression de page travaille au niveau de la page. Cette technique recherche les valeurs ayant le mme dbut et les doublons afin de les stocker dans un dictionnaire. Cette mthode est comparable celle d'Oracle, hormis le fait qu'elle travaille, en plus, sur les dbuts des valeurs et pas seulement sur les valeurs entires. La compression des donnes s'active l'aide de l'option de table DATA_COMPRESSION avec les options suivantes: DATA_COMPRESSION = { NONE | ROW | PAGE }

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 121

Gestion des LOB

Les LOB (Large Object correspondant aux types CLOB et BLOB) sont stocks dans un segment spar de celui du tas. Cependant, par dfaut, la clause ENABLE STORAGE IN ROW est active. De ce fait, les LOB dune taille infrieure 4Ko sont stocks avec le reste de lenregistrement, alors que les LOB plus gros sont stocks dans le segment spar. Cela risque de ralentir les Table Scan ne ncessitant pas les donnes LOB car il y a plus de blocs lire que si les donnes LOB taient toutes dans un segment spar. Toutefois, ce mode de stockage permet dacclrer la rcupration des enregistrements avec des petits LOB en vitant les accs supplmentaires au segment LOB. Selon le type daccs dont vous avez besoin, il faudra choisir le mode le plus adapt. Si vous ne rcuprez jamais les LOB dans les Table Scan mais seulement en accs monoenregistrement, il sera peut-tre pertinent de les stocker sparment. Laisser le stockage des petits LOB activ en ligne a pour effet dagrandir la zone tas de la table. Par contre, cela vite des va-et-vient entre le tas et le segment LOB pour les petites donnes contenues dans les champs LOB. Pour spcifier cette option, il faut ajouter dans la clause STORAGE de la table:
lob (<LeChampLob>) store as <NomDuSegment> (disable storage in row CHUNK 8K);

est le nom du segment qui contiendra idalement le nom de la table et du champ, par exemple SegLob_Matable_Monchamp. Le paramtre CHUNK contient la taille utilise pour les allocations despace LOB pour une donne dans le segment LOB. Cette valeur est forcment un multiple de la taille du bloc (8Ko par dfaut). Pour des fichiers, la taille initiale de 8Ko et le fait de dsactiver le stockage en ligne sont adapts, alors que pour des champs CLOB qui sont des champs texte potentiellement gros, ce choix nest pas toujours judicieux. Cela entranera la cration de beaucoup de blocs de 8Ko, pleins de vide, pour rien si ce sont des petites chanes. Ayez bien conscience que si vous dsactivez le stockage en ligne, un CLOB de 10caractres occupera 8Ko.
NomDuSegment

Compression des LOB

La version 11g Release 1 a introduit la notion de SecureFiles pour stocker les champs LOB. Une des options intressantes du point de vue de loptimisation est la compression des champs LOB. Compltement transparente, elle a seulement un impact sur les performances, surtout lors des oprations dcriture. Elle nest adapte que pour des donnes qui se compressent bien. Il est donc sans intrt dactiver

122

tude et optimisation desrequtes

Axe 2

la compression dun LOB destin stocker des formats dj compresss (JPEG, MPEG, ZIP, Audio,etc.).
lob (<LeChampLob>) store as <NomDuSegment> (compress [ HIGH | MEDIUM | LOW ]);

Sur notre table exemple, contenant des pages de livres, nous obtenons un gain despace de 30%. Le parcours squentiel du champ LOB sur plusieurs enregistrements est en toute logique pnalis, mais ce nest gnralement pas lopration la plus frquente sur ce type de champ. En revanche, la recherche via un index Full Text nest, en toute logique, pas du tout affecte puisque seul lindex est utilis. Dans ce cas-l, seule la manipulation des LOB est impacte. SecureFiles met aussi disposition une fonction de dduplication de donnes laide de loption DEDUPLICATE. Celle-ci entrane, elle aussi, une surcharge significative mais seulement en criture. Elle peut ventuellement tre intressante si vos donnes sy prtent, cest--dire si plusieurs enregistrements contiennent exactement la mme valeur. Sur la table exemple livres, qui contient les donnes en quatre exemplaires, cela fonctionne bien, mais il semble que cette option ait pour effet de dsactiver le stockage en ligne, ce qui, dans notre cas, est pnalisant.
5.3.2 Index Organized Table

Pour rappel, la structure dune table classique organise en tas (heap) ou HOT (Heap Organized Table) utilisant des index B*Tree est la suivante(voir Figure 5.14a). Les IOT (Index Organized Table) ont une organisation sensiblement diffrente puisquelles intgrent les donnes dans lindex de cl primaire (voir Figure 5.14b). Sur une table organise en tas, le tas et la cl primaire sont deux objets distincts alors que sur une table de type IOT, ils sont confondus. Cette organisation prsente les avantages suivants: Gain despace. Il nest plus ncessaire: de dupliquer les donnes de la cl primaire entre le tas et l'index; de stocker les RowID permettant de faire le lien entre l'index B*Tree et le tas. Gain en possibilit dusage de lindex. Au-del de 5% de la table parcourir, on estime quil nest plus intressant dutiliser un index classique cause des va-et-vient entre lui et le tas. Cette rgle ne sapplique pas de la mme faon aux IOT, qui nont pas ces problmes puisque lindex de cl primaire et les donnes sont confondus.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 123

1 000 2 000 15 000 16 000 20 000 50 000 150 000 240 000 35 000 47 000 20 000 21 000

0 1 998 999 1 000 1 015 1 700 1 900

ROWID ROWID

4 521 582

LECLERC DUPOND ROCHE

OPRATEUR

COMMERCIAL

ROWID ROWID ROWID ROWID

874

COMMERCIAL MANAGER

1 015 BERTHIER 2 586 325 MARTIN GUY BERGER LEGRAND

COMMERCIAL MANAGER

ROWID ROWID

1 999

COMMERCIAL MANAGER

Bloc Racine Root Blocks

Blocs Branche Branch Blocks

Blocs Feuille Leaf Blocks

Table Heap : Donnes non ordonnes

Figure5.14a Table Heap et un index. Figure5.14b Structure d'une table IOT

Le RowID permet de pointer sur les lignes stockes dans le Tas

1 000 2 000 15 000 16 000 20 000 50 000 150 000 240 000 35 000 47 000 20 000 21 000

0 1 998 999 1 000

DUPONT BERGER MEUNIER LEGRAND DUPIC

COMPTABLE

COMMERCIAL

COMMERCIAL MANAGER

COMMERCIAL MANAGER MANAGER ACHETEUR

1 015 BERTHIER 1 700 DUVAL

Bloc Racine Root Blocks

1 900 NEUVILLE

Blocs Branche Branch Blocks

Blocs Feuille Leaf Blocks Les donnes sont dans les feuilles du B*Tree

124

tude et optimisation desrequtes

Axe 2

Toute mdaille ayant son revers, voil les principaux inconvnients des IOT: La modification des valeurs de la cl primaire ou linsertion non squentielle provoquent des mouvements de donnes plus importants puisque cela peut conduire dplacer des lignes et non pas juste des cls dans des index. Les index secondaires ncessitent plus despace (voir ci-aprs la section "index B*Tree et IOT"). Les cas o le parcours seul de lindex de cl primaire rpond la demande seront moins performants car, prsent, parcourir lindex de cl primaire revient parcourir la table, ce qui se traduira gnralement par plus de donnes manipuler.
Mise en uvre

La dclaration dune table organise en index (IOT) se fait, dans le CREATE TABLE, par la spcification de lorganisation INDEX (au lieu de HEAP par dfaut). Il nest pas possible de convertir une table HOT en IOT et vice versa.
Create table xxx ( . . . ) ORGANIZATION INDEX;

Index B*Tree et IOT

Sur une table de type IOT, la cl primaire est intgre, mais il est cependant possible de crer des index secondaires sur dautres colonnes, comme sur les tables organises en tas. Ces index seront dune nature un peu diffrente. Les index B*Tree contiennent habituellement, pour chaque entre, la cl de lindex plus le RowID pointant sur une position dans le tas. Cependant, il existe une diffrence majeure entre les deux formats de table: sur celles organises en tas, les lignes ne bougent pas dans le tas, alors que sur celles de type IOT, elles peuvent tre dplaces car elles doivent respecter lordre de la cl primaire. Cela signifie que lemploi dun RowID pour dsigner les enregistrements sur les index secondaires des tables de type IOT est dlicat. On ne peut pas envisager de mettre jour tous les index chaque mouvement de ligne. Il faudrait pour cela retrouver et modifier les entres correspondantes dans tous les index, ce qui serait particulirement pnalisant. Donc, les index B*Tree sur IOT ne contiennent pas de RowID pour retrouver la ligne pointe mais un Logical RowID plus la cl primaire. Le Logical RowID est le numro du bloc dans lequel tait la ligne au moment de linsertion. Cest donc lendroit o elle devrait toujours tre, puisquon suppose dans un IOT que les donnes sont insres squentiellement. Cependant, au cas o lenregistrement aurait boug, on utiliserait les donnes de la cl primaire places dans lindex pour retrouver lenregistrement en parcourant le B*Tree de la table.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 125

Les index B*Tree sur IOT contiennent la cl de lindex, Logical RowID linsertion et la cl primaire. Ils sont donc plus gros que les index sur les tables organises en tas. Cest dautant plus vrai que la cl primaire sera grosse. On veillera ne pas avoir trop dindex secondaires sur les tables IOT qui nont pas une cl primaire de petite taille. De plus, si la table est mouvemente et que cela conduise des dplacements denregistrements dans dautres blocs, le Logical RowID contenu dans lindex conduira souvent au mauvais bloc. Il faudra alors parcourir le B*Tree de la cl primaire pour trouver lenregistrement demand, ce qui provoquera inutilement quelques oprations supplmentaires. Ce type de problme ne fera quaugmenter au fil du temps car il y aura de plus en plus de dplacements denregistrements. Une reconstruction de lindex permettra de refaire pointer les Logical RowID sur les blocs adquats.
Index bitmap et IOT

Pour mettre en uvre un index bitmap sur un IOT, il faut que la table possde une table de mapping, spcifiant les paramtres suivants lors de la cration de la table:
ORGANIZATION INDEX MAPPING TABLE

Impact sur les oprations LMD

Lorganisation IOT des tables est un peu moins performante que lorganisation en tas si on insre des donnes de faon non linaire par rapport la cl primaire. Cependant, mme dans ce cas, ce nest pas dsastreux au moment de linsertion car elle a lieu dans un B*Tree. Par contre, cela risque de provoquer des dplacements denregistrements et, du coup, leffet sera peut-tre plus notable sur les donnes existantes car les index secondaires auront des Logical RowID errons, ce qui entranera des accs supplmentaires lors des requtes SELECT. la suite de nombreuses mises jour sur les cls ou dinsertions non squentielles, des "trous" peuvent apparatre dans la table. Il sera alors peut-tre judicieux de la rorganiser afin de la compacter.
ALTER TABLE clients_iot MOVE ONLINE;

Tableau5.3: Comparaison des temps de mise jour des cls de 30% de la table

Paramtre Temps Consistent Gets CPU

Table HEAP 0,89s 322 39

Table IOT 6,047s 21918 201

update clients set NOCLIENT=NOCLIENT+1000000 where pays='USA'

126

tude et optimisation desrequtes

Axe 2

Avant sa mise jour, la table clients en organisation IOT occupait 6144Ko, aprs, elle occupe 8192Ko. Cela est li au fait que les enregistrements ont t dplacs de leurs feuilles existantes pour aller dans de nouvelles feuilles. La plus grande valeur tait 145000 avant la mise jour et celle-ci a dplac les enregistrements modifis dans des feuilles situes au-del de cette valeur.
Tableau5.4: Comparaison des performances d'un index secondaire sur une table organise en IOT avant et aprs dplacement des cls

Paramtre Consistent Gets CPU

Avant 3570 0

Aprs 4408 2

select count(nom) from clients where pays='Japan'; update clients set NOCLIENT=NOCLIENT+1000000 where pays='Japan'; select count(nom) from clients where pays='Japan';

Il y a une augmentation de 25% des Consistent Gets lie au fait que les enregistrements ne sont plus l o ils devraient tre, daprs les Logical RowID, ce qui provoque des parcours de lindex intgr de la cl primaire.
valuation de l'espace occup

Concernant le gain despace, si nous testons sur notre base exemple avec la table cmd: Taille du tas (26Mo) + Index cl primaire (30Mo) = 56Mo. Taille IOT = 28Mo. On constate un gain significatif. De faon gnrale, la taille de lIOT sera lgrement plus grande que la taille du tas, lcart tant constitu des branches du B*Tree. Il est noter que plus lindex de cl primaire compte de colonnes et moins les enregistrements en ont, plus le ratio despace conomis est important par rapport une table organise en tas (ce qui est le cas dans notre exemple). Par contre, si nous regardons lvolution de la taille de lindex secondaire sur la colonne Noclient, nous voyons que, sur la table organise en tas, il occupe 18Mo alors que, sur la table de type IOT, il occupe 25Mo soit presque 40% de plus alors que la cl primaire est plutt petite puisque cest une valeur numrique.
Overflow segment

Comme nous lavons vu prcdemment, une table de type IOT a pour effet de pnaliser les oprations pouvant se faire uniquement sur lindex de la cl primaire, puisque lindex contient prsent lensemble des champs. Afin de rduire cet impact, il est

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 127

possible de mettre en uvre un segment de dbordement (overflow segment), qui est, en fait, une table organises en tas contenant une partie des champs. Cette solution fait chuter les performances quand il faut souvent rcuprer les donnes qui sont dans ce segment par exemple, dans le cas dun Full Table Scan qui aurait besoin des donnes qui sont situes dans le segment de dbordement. Par contre, dans les autres cas, les performances sont meilleures car la partie index de la table IOT est moins volumineuse. La mise en uvre se fait avec les mots cls OVERFLOW et INCLUDING qui prcisent la dernire colonne tre dans la partie index, les colonnes suivantes seront donc dans le segment de dbordement (ci-aprs: Jobhistory et Managercomments).
CREATE TABLE IOTEMPOverflow ( EMPNO NUMBER , VARCHAR2(10) NOT NULL , ENAME JOB VARCHAR2(9) , JobHistory VARCHAR2(4000), ManagerComments VARCHAR2(4000), constraint PK_IOTEMPOverflow primary key(empno)) Organization index including JOB overflow ;

MS SQL Server
Nous retrouvons sous SQL Server la mme fonctionnalit sous le nom de Clustered Index. La cration d'un index clustered (un seul possible par table) aura pour effet de transformer la table d'une organisation en tas en une organisation en index. Par dfaut, une cl primaire cre un index de type clustered. Donc, si le contraire n'est pas spcifi, toute table qui a une cl primaire est de type Index Organized Table. Dans l'instruction CREATE TABLE, la clause CONSTRAINT permet de prciser le type d'index: CONSTRAINT constraint_name { { PRIMARY KEY | UNIQUE } [ CLUSTERED | NONCLUSTERED ] } Les index secondaires sont par dfaut NON CLUSTERED : CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name ON <object> ( column [ ASC | DESC ] [ ,...n ] ) Concernant les index secondaires sur table IOT, contrairement ce qui se passe avec Oracle, l'index ne contient pas de Logical RowID mais seulement la cl de la table. Cela a pour effet de moins pnaliser les index secondaires sur IOT de SQL Server que sur Oracle si les enregistrements changent de bloc mais ils seront un peu moins performants si la table a une croissance respectant l'ordre de la cl. L'index souffre par contre du mme problme de taille si la cl primaire n'est pas petite, bien que cela soit un peu rduit par l'absence du Logical RowID.

128

tude et optimisation desrequtes

Axe 2

MySQL
Le moteur InnoDB utilise un stockage de type IOT exclusivement. Le moteur MyISAM ne propose pas d'option pour implmenter les IOT. C'est donc le type de la table dans les instructions CREATE TABLE et ALTER TABLE qui dcidera du type de l'organisation de la table. CREATE TABLE tbl_name (create_definition,...) {ENGINE|TYPE} = {InnoDB| MYISAM}

valuation des performances

Effectuons un premier test sur une requte portant uniquement sur les index:
select count(*) from cmd_lignes

Figure5.15 Trace d'excution sur une table Heap.

Figure5.16 Trace d'excution sur une table IOT.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 129

Les requtes portant uniquement sur lindex de cl primaire sont plus rapides sur des table organises en tas plus B*Tree car lindex B*Tree est plus petit (56Mo) que la table IOT (75Mo). Sur la table organise en IOT, on constate un Index Fast Full Scan, ce qui est quivalent un Full Table Scan sur une table organise en tas. Sur les requtes ncessitant uniquement lutilisation dindex secondaires, lavantage sera l aussi aux tables organises en tas car, nous lavons vu, les index secondaires sont plus petits sur les tables organises en tas que sur les tables IOT, mais lcart sera gnralement moindre quavec lusage de la cl primaire. Nous allons faire un deuxime test portant sur un parcours dintervalles de la cl primaire ncessitant daccder des colonnes non indexes. La requte ci-aprs travaille sur une plage de 5477enregistrements
select sum(montant) from cmd_lignes where nocmd between 100000 and 102000;

On constate que loptimiseur dcide deffectuer un Range Scan sur lindex de cl primaire pour rcuprer les enregistrements correspondants par leur RowID afin deffectuer le calcul de la somme.
Figure5.17 Trace d'excution sur une table organise en tas.

la Figure5.18, on voit que le SGBDR scanne uniquement la partie de la table concerne et rcupre les donnes dans la mme passe. On a un meilleur temps de rponse et moins de Consistent Gets. Cest le cas de prdilection de lIOT1.

1. En fonction du facteur de foisonnement des donnes du test ralis sur la table organise en HEAP, le gain pourrait tre encore plus important.

130

tude et optimisation desrequtes

Axe 2

Figure5.18 Trace d'excution sur une table organise en IOT.

Nous allons raliser un troisime test, analogue au prcdent mais portant sur un intervalle plus important. La requte ci-aprs travaille sur un intervalle de 261205enregistrements, soit 10% de la table.
select sum(montant) from cmd_lignes where nocmd between 100000 and 200000

Sur la table organise en tas, loptimiseur choisit de faire un Full Table Scan sans laisser la table en cache (visible car chaque excution contient des Physical Reads) [voir Figure5.19].
Figure5.19 Requte sur une table organise en tas.

Sur la table organise en index (IOT), loptimiseur fait un Range Scan en suivant la cl primaire, ce qui est toujours le cas de prdilection des IOT. De plus, il laisse la table en cache, probablement cause de son statut dindex (voir Figure5.20).

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 131

Si on augmente encore lintervalle pour couvrir 50% de la table, on constate que loptimiseur ne choisit plus de faire dIndex Range Scan sur lIOT mais un Index Fast Full Scan. Cela vient probablement du fait quun Index Range Scan parcourt les blocs dans lordre de lindex et effectue donc des lectures alatoires alors quun Index Fast Full Scan privilgie des lectures squentielles en lisant les blocs dans lordre du segment. Or, selon la performance du disque ou selon que les donnes soient en cache ou pas, le surcot dune lecture alatoire compare une lecture squentielle peut se rduire de faon significative par rapport aux cots estims qui sont de 5656 pour la version Full Scan et de 10401 pour la version Range Scan. Si nous forons un Index Range Scan laide du hint INDEX_RS, nous constatons une rduction des Consistent Gets de 9109 4535 et une rduction du temps dexcution de 1,43 seconde 0,91 seconde, nous avons donc un rsultat diffrent de lestimation de loptimiseur.
Figure5.20 Requte sur une table organise en IOT.

Nous pourrions penser que cela est d au fait que les donnes sont dans le cache, mais si nous excutons linstruction alter system flush buffer_cache; pour vider le cache et que nous rexcutions les requtes, nous trouverons des quantits de Physical Reads et de Consistent Gets trs proches. Malgr tout, nous observons la mme tendance, la version Range Scan sexcute en 3,78secondes et la version Full Scan en 6,15secondes. Les choses pourraient tre diffrentes suivant la faon dont la table a t remplie, les performances des disques, etc. Donc, comme toujours, testez!
select /*+index_rs(t)*/ sum(montant) from cmd_lignes_iot t where nocmd between 100000 and 600000

132

tude et optimisation desrequtes

Axe 2

5.3.3

Cluster

Le cluster est un objet doptimisation qui existe depuis longtemps dans les bases Oracle mais qui na jamais connu de franc succs, ce qui, de mon point de vue, est tout fait justifi tant donn les problmes quil pose. Ce chapitre a donc pour principal objet dexpliquer le fonctionnement des clusters et la raison pour laquelle ils ne vont probablement pas vous convenir. Je nexclus cependant pas le fait que, dans quelques cas, ils puissent tre intressants. Un cluster est un regroupement entre deux tables pour simplifier, on pourrait dire quun cluster est une jointure forte. Cest un objet qui est orient pour des tables ayant entre elles une relation matre/dtails. Lide est que le cluster va stocker dans une mme zone ces deux tables au lieu de les stocker dans deux zones distinctes. Il pousse mme la chose jusqu stocker les enregistrements matres et les enregistrements dtails dans le mme bloc de donnes. Lintrt rside dans le fait que, lorsque vous faites une jointure entre ces deux tables, en lisant un seul bloc vous rcuprez les donnes matres et dtails et en plus il ny a pas de choses compliques faire pour raliser la jointure. Pour linstant, le cluster a lair formidable, voyons donc o est le problme. Afin de pouvoir stocker les enregistrements dtails avec lenregistrement matre, le cluster va rserver un bloc (soit gnralement 8Ko) pour chaque cl, ce qui risque davoir pour effet de faire exploser lespace ncessaire pour stocker les donnes et ainsi daugmenter le nombre dE/S, ce qui sera finalement assez pnalisant. Par exemple, sur notre base de test, o nous allons nous limiter 100000commandes au lieu dun million: Tas et cl primaire de cmd + cmd_lignes = 56Mo + 130Mo = 186Mo pour un million de commandes soit environ 20Mo pour 100000commandes. Cluster CLUS_CMD plus les index = 811Mo + 9Mo + 4Mo + 3Mo = 827Mo soit un peu plus de 40fois plus. Avec une taille de bloc de 2Ko (la plus petite valeur possible) au lieu 8Ko, lespace occup ne serait plus que de 200Mo ce qui est encore 10fois plus que sans cluster. Exemple de cration de tables dans un cluster:
create cluster CLUS_CMD (NoCmd number) size 8k; Create Index IDX_CLUS_CMD ON CLUSTER CLUS_CMD; Create Table CMD_CLUS ( NOCMD NUMBER not null,

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 133

NOCLIENT NUMBER, DATECOMMANDE DATE, ETATCOMMANDE CHAR(1), Constraint PK_clus_CMD primary key (NoCmd)) cluster CLUS_CMD(NoCmd); Create Table CMD_LIGNES_CLUS ( NOCMD NUMBER not null, NOLIVRE NUMBER not null, QUANTITE NUMBER, REMISE NUMBER, MONTANT NUMBER, constraint PK_CLUS_CMD_LIGNES primary key (NOCMD, NOLIVRE), constraint FK_CLUS_CMD_LIGNES_CMD foreign key (NOCMD) references CMD_ CLUS(NOCMD) ) cluster CLUS_CMD(NOCMD); insert into CMD_CLUS commit; select * from CMD where nocmd <114524;

insert into CMD_LIGNES_CLUS select * from CMD_LIGNES where nocmd <114524; commit;

valuation

Nous allons vrifier avec quelques tests si cette mauvaise rputation est mrite ou pas. Nous allons excuter la requte suivante qui porte sur quelques milliers denregistrements (10000commandes et 25000lignes de commandes) et utilise des donnes de la table matre cmd et de la table dtails cmd_lignes en filtrant par la cl du cluster, savoir le champ Nocmd (cas dutilisation optimale du cluster). Cet exemple est un peu compliqu, le champ Montantremisemardi a seulement pour but dempcher loptimiseur de simplifier la requte afin de forcer la jointure.
select avg(montanttotal) MontantMoyen,avg(NbrItem)NbrItemMoyen, sum(NbrItem) NbrTotalItem,count(distinct nocmd) NbrCmd, sum(montanttotal) MontantTotal,sum(MontantRemiseMardi) TotalRemiseMardi from ( select c.nocmd,c.datecommande,sum(montant) montanttotal,count(*) NbrItem ,sum(case when to_char(c.datecommande,'d')=2 then montant*0.03 else 0 end) MontantRemiseMardi from cmd_clus c join cmd_lignes_clus cl on c.nocmd=cl.nocmd where c.nocmd between 70000 and 80000 group by c.nocmd, c.datecommande );
MONTANTMOYEN NBRITEMMOYEN NBRTOTALITEM NBRCMD MONTANTTOTAL TOTALREMISEMARDI ------------ ------------ ------------ ---------- ------------ ---------------221,324 2,488 24884 10001 2213465,18 7977,66

134

tude et optimisation desrequtes

Axe 2

Nous constatons un avantage significatif en temps dexcution pour la solution cluster car pour notre test les blocs impliqus restent dans le cache. Si nous vidons le cache laide de linstruction alter system flush buffer_cache;, la solution cluster ncessite 10 038 Physical Reads et 11,7 secondes contre 5,7 secondes et 8360Physical Reads. La tendance se confirme de la mme faon, en dfaveur du cluster, si nous augmentons la taille de lintervalle parcourir qui aura pour effet daugmenter le nombre de blocs et donc de rduire leur probabilit de prsence en cache. Le cot estim par loptimiseur de chacune des solutions confirme dailleurs cette tendance dfavorable pour le cluster. La solution cluster est donc intressante sil y a assez denregistrements pour quune jointure soit coteuse, mais pas trop, pour que la taille ne devienne pas pnalisante. Pour la plupart des autres cas, le cluster sera viter. Cela laisse une plage dintrt assez rduite. Si votre problmatique sy trouve, alors il peut y avoir des gains significatifs, mais si ce nest pas clairement le cas, je vous conseille de rester lcart de cet objet qui peut vous faire payer assez cher le fait de lavoir choisi tort.
Figure5.21 Trace d'excution sans cluster.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 135

Figure5.22 Trace d'excution avec cluster.

5.3.4

Partitionnement des donnes

Le partitionnement permet de diviser une grosse table en morceaux physiquement plus petits (les partitions), tout en gardant la vision logique dune grosse table. Ilsera possible deffectuer des oprations de maintenance sur les partitions individuellement, ce qui permettra daugmenter la disponibilit des donnes. Les partitions sont cres partir des valeurs des colonnes qui seront dfinies comme les cls de partitionnement. Il peut y avoir jusqu 16colonnes et elles doivent tre spcifies NOT NULL. Une table peut tre divise en 64000partitions au plus. Oracle11g Release1 introduit la possibilit de partitionner suivant une colonne calcule en autorisant le partitionnement sur des colonnes virtuelles. Le partitionnement nest pas disponible sur toutes les ditions dOracle (idem pour MySQL et MS SQL Server). Du point de vue de loptimisation, le principal intrt des partitions est que lorsque loptimiseur pourra dterminer les partitions ncessaires, les requtes nutiliseront que celles-ci et ignoreront les autres, ce qui amliorera les performances. Il faut donc, lorsque vous utilisez des tables partitionnes, essayer le plus possible de mettre des conditions qui permettent de slectionner les partitions concernes. Lautre intrt est de pouvoir spcifier les tablespaces associs chaque partition, et ainsi de rpartir les donnes sur diffrents volumes afin daugmenter les dbits et de pouvoir parallliser au mieux. Il sera possible, a posteriori, de fusionner, diviser et dplacer chacune des partitions.

136

tude et optimisation desrequtes

Axe 2

Le partitionnement occupe, presque lui seul, un livre entier dans la documentation Oracle. Le but ici nest pas dtre exhaustif, mais de donner quelques cls pour juger si sa mise en uvre est pertinente pour vous, et si elle lest, de vous donner les bases.
Mise en uvre

Il est possible de partitionner les tables (HEAP ou IOT) et les index (B*Tree ou bitmap) et de les combiner de diffrentes faons (voir Figure 5.23):

table et index partitionns suivant le mme dcoupage (relativement frquent); table partitionne et index non partitionn (relativement frquent); table non partitionne et index partitionn (plutt rare).
Index partitionn 2007 2007 2008 2008 2009 2009 2007 Index non partitionn 2007 - 2009 2008 2009 Index partitionn 2007 2008 2009

Figure5.23 Combinaisons possibles entre tables partitionnes et index partitionns.

2007 - 2009

Table partitionne

Table partitionne

Table non partitionne

Il existe principalement trois types de partitionnement:


Figure5.24 Principaux types de partitionnement.
Partitionnement par liste
Allemagne, France, Espagne

Partitionnement par intervalle 2005 2007

Partitionnement par hachage Partition 1 Partition 2

Europe

USA, Brsil, Mexique

Amrique

2008

Partition 3 Partition N

Sngal, Cameroun, Bnin

Afrique

2009

Autres

2010

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 137

Partitionnement par liste

Il permet de dfinir pour chaque partition la liste des valeurs qui la constituent plus la valeur DEFAULT qui reprsente toutes les autres valeurs possibles. Ci-aprs un exemple du partitionnement de la table clients par la colonne Pays.
create table CLIENTS_PART ( NOCLIENT NUMBER not null, NOM VARCHAR2(50), PRENOM VARCHAR2(50), ADRESSE1 VARCHAR2(100), ADRESSE2 VARCHAR2(100), CODEPOSTAL VARCHAR2(10), VILLE VARCHAR2(50), PAYS VARCHAR2(50), TEL VARCHAR2(20), EMAIL VARCHAR2(50), constraint PK_CLIENTS_PART primary key (NOCLIENT) ) PARTITION BY LIST(PAYS) ( PARTITION Clients_Amerique VALUES('USA','Brsil','Mexique') tablespace TableSpace1, PARTITION Clients_Europe VALUES ('Allemagne','France','Espagne') tablespace TableSpace2, PARTITION Clients_Afrique VALUES('Sngal','Cameroun','Bnin') tablespace TableSpace3, PARTITION Clients_Autres VALUES(DEFAULT) tablespace TableSpace2 );

Partitionnement par intervalle

Il permet de dfinir pour chaque partition lintervalle de valeurs qui la constituent en spcifiant la borne suprieure. Si une valeur est suprieure la plus grande borne, lopration choue. Pour tre sr de nexclure aucune valeur, il suffit de spcifier la valeur MAXVALUE qui reprsente la plus grande valeur possible.
create table CMD_PART( NOCMD NUMBER not null, NOCLIENT NUMBER, DATECOMMANDE DATE, ETATCOMMANDE CHAR(1), constraint PK_CMD_PART primary key (NOCMD) ) PARTITION BY RANGE(DATECOMMANDE) ( PARTITION CMD_2005_2007 VALUES LESS THAN(TO_DATE('01/01/2008','DD/MM/YYYY')) TABLESPACE TableSpace1, PARTITION CMD_2008 VALUES LESS THAN(TO_DATE('01/01/2009','DD/MM/YYYY')) TABLESPACE TableSpace2, PARTITION CMD_2009_MAX VALUES LESS THAN(MAXVALUE) TABLESPACE TableSpace3 );

138

tude et optimisation desrequtes

Axe 2

Oracle 11g introduit une variante qui se nomme, en anglais, interval partitioning. Elle permet de crer automatiquement les partitions au-del de la dernire limite dfinie, suivant une frquence tablie sur un champ numrique ou date.
create table CMD_PART( NOCMD NUMBER not null, NOCLIENT NUMBER, DATECOMMANDE DATE, ETATCOMMANDE CHAR(1), constraint PK_CMD_PART primary key (NOCMD) ) PARTITION BY RANGE(DATECOMMANDE) INTERVAL (NUMTOYMINTERVAL(1,'YEAR')) ( PARTITION CMD_2005_2007 VALUES LESS THAN(TO_DATE('01/01/2008','DD/MM/YYYY')) TABLESPACE TableSpace1, PARTITION CMD_2008 VALUES LESS THAN(TO_DATE('01/01/2009','DD/MM/YYYY')) TABLESPACE TableSpace2, PARTITION CMD_2009 VALUES LESS THAN(TO_DATE('01/01/2010','DD/MM/YYYY')) TABLESPACE TableSpace3 );

Partitionnement par hachage

Dans ce type de partitionnement, on dfinit seulement la liste des partitions et la colonne qui sert de paramtre pour calculer la cl de hachage. Cette solution est la plus simple mettre en uvre, mais probablement la moins pratique pour dterminer la manire doptimiser lusage des partitions.
create table CMD_PART_HASH( NOCMD NUMBER not null, NOCLIENT NUMBER, DATECOMMANDE DATE, ETATCOMMANDE CHAR(1), constraint PK_CMD_PART_HASH primary key (NOCMD) ) PARTITION BY HASH(NOCMD) PARTITIONS 4 STORE IN (Tablespace1, Tablespace2, Tablespace3, Tablespace4);

Partitionnement systme

Introduit en version 11g, il permet de ne donner aucune rgle de rpartition des donnes entre les partitions la cration de la table mais de grer cette rpartition dans les instructions INSERT laide du paramtre PARTITION. De la mme faon, il sera possible de spcifier au niveau des instructions UPDATE, DELETE et SELECT sur quelle partition porte la requte. La syntaxe dans linstruction CREATE TABLE est la suivante:

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 139

PARTITION BY SYSTEM ( PARTITION Partition1, PARTITION Partition2 );

Les requtes dinsertion sur ces tables doivent spcifier la partition utilise laide du mot cl PARTITION.
insert into TablePartitionnee partition (Partition1) values (. . .);

Pour les requtes UPDATE, DELETE et SELECT, cette directive est optionnelle. Son absence entrane un parcours de toutes les partitions. Il peut y avoir incohrence entre la partition dsigne et les autres prdicats, puisque ce point relve de la responsabilit du dveloppeur.
delete TablePartitionnee partition (Partition1) where . . .; select * from TablePartitionnee partition (Partition1) where . . .;

Partitionnement combin

On peut combiner deux types de partitionnement afin de faire un partitionnement composite. Cela signifie que vous pourrez spcifier deux axes de partitionnement. Vous pouvez faire un sous-partitionnement rgulier, cest--dire dcouper toutes les partitions en sous-partitions identiques laide de SUBPARTITION TEMPLATE, ou un sous-partitionnement libre, qui sera propre chaque partition mme si le champ permettant le sous-partitionnement est commun toutes les sous-partitions. Lexemple suivant illustre les deux syntaxes possibles. Jusqu la version10g, les seules combinaisons possibles taient partition par intervalle et sous-partition par Hash ou partition par intervalle et sous-partition par liste. La version 11g a introduit les possibilits suivantes : Intervalle/Intervalle, Liste/ Intervalle, Liste/Hash, Liste/Liste.
Figure5.25 Exemple de partitionnement combin.
Table CLIENTS avec partitionnement combin
Allemagne France Espagne

Europe

Amrique
USA Brsil Mexique

Sngal Cameroun Bnin

Afrique

Chine Japon Indonsie

Asie

Partitionnement par Pays Partitionnement par N client Anciens Clients Noclient < 30 000

Sous-partition Sous-partition Sous-partition Sous-partition

Nouveaux Clients Noclient 30 000

Sous-partition Sous-partition Sous-partition Sous-partition

140

tude et optimisation desrequtes

Axe 2

Exemple de cration d'une table avec des sous-partitions rgulires


create table CLIENTS_PART( NOCLIENT NUMBER not null, NOM VARCHAR2(50), PRENOM VARCHAR2(50), ADRESSE1 VARCHAR2(100), ADRESSE2 VARCHAR2(100), CODEPOSTAL VARCHAR2(10), VILLE VARCHAR2(50), PAYS VARCHAR2(50), TEL VARCHAR2(20), EMAIL VARCHAR2(50), constraint PK_CLIENTS_PART primary key (NOCLIENT) ) PARTITION BY LIST(PAYS) SUBPARTITION BY RANGE (NOCLIENT) SUBPARTITION TEMPLATE( SUBPARTITION Anciens VALUES LESS THAN (30000) TABLESPACE TableSpace1, SUBPARTITION Recents VALUES LESS THAN (MAXVALUE) TABLESPACE TableSpace2) ( PARTITION Clients_Amerique VALUES('USA', 'Canada','Brazil'), PARTITION Clients_Europe VALUES ('Germany', 'United Kingdom', 'France','Italy'), PARTITION Clients_Asie VALUES('Japan', 'China','India'), PARTITION Clients_Autres VALUES(DEFAULT) );

Exemple de cration d'une table avec des sous-partitions libres


create table CLIENTS_PART( NOCLIENT NUMBER not null, NOM VARCHAR2(50), PRENOM VARCHAR2(50), ADRESSE1 VARCHAR2(100), ADRESSE2 VARCHAR2(100), CODEPOSTAL VARCHAR2(10), VILLE VARCHAR2(50), PAYS VARCHAR2(50), TEL VARCHAR2(20), EMAIL VARCHAR2(50), constraint PK_CLIENTS_PART primary key (NOCLIENT) ) PARTITION BY LIST(PAYS) SUBPARTITION BY RANGE (NOCLIENT) ( PARTITION Clients_Amerique VALUES('USA', 'Canada','Brazil') (SUBPARTITION Clients_AM_Anciens VALUES LESS THAN (30000) TABLESPACE Tablespace1, SUBPARTITION Clients_AM_Recents VALUES LESS THAN (MAXVALUE) TABLESPACE Tablespace2), PARTITION Clients_Europe VALUES ('Germany', 'UK', 'France','Italy') (SUBPARTITION Clients_EU_Anciens VALUES LESS THAN (30000) TABLESPACE Tablespace3,

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 141

SUBPARTITION Clients_EU_Recents VALUES LESS THAN (MAXVALUE) TABLESPACE Tablespace4), PARTITION Clients_Asie VALUES('Japan', 'China','India') (SUBPARTITION Clients_AS_Anciens VALUES LESS THAN (30000) TABLESPACE Tablespace5, SUBPARTITION Clients_AS_Recents VALUES LESS THAN (MAXVALUE) TABLESPACE Tablespace6), PARTITION Clients_Autres VALUES(DEFAULT) (SUBPARTITION Clients_AU_Anciens VALUES LESS THAN (30000) TABLESPACE Tablespace7, SUBPARTITION Clients_AU_Recents VALUES LESS THAN (MAXVALUE) TABLESPACE Tablespace8) );

Partitionnement par rfrence

Oracle 11g Release1 a introduit une nouvelle mthode assez intressante. Elle permet de partitionner une table en fonction des valeurs contenues dans une autre table et ayant une relation de rfrence au moyen dune cl trangre (Foreign Key) avec elle. Ce type de partitionnement a t introduit pour grer des relations de type matre/dtails. Ci-aprs, un exemple entre la table des commandes et la table des lignes de commandes est propos:
create table CMD_LIGNES_PART( NOCMD NUMBER not null, NOLIVRE NUMBER not null, QUANTITE NUMBER, REMISE NUMBER, MONTANT NUMBER, constraint PK_CMD_LIGNES_PART primary key (NOCMD, NOLIVRE), constraint FK_CMD_LIGNES_CMD_PART Foreign key (NOCMD) References CMD_ PART(NOCMD) ) PARTITION BY REFERENCE (FK_CMD_LIGNES_CMD_PART);

Partitionnement et index

Il existe trois types dindex travaillant avec les partitions:

Les index normaux, qui permettent dindexer des colonnes de faon indpendante des partitions de la table. Les index locaux prfixs, qui sont calqus sur les partitions et qui reprennent en premires colonnes les colonnes de la cl de partitionnement. Les index locaux non prfixs, qui sont calqus sur les partitions et qui ne reprennent pas les colonnes de la cl de partitionnement. Ces index-l ne peuvent pas tre de type unique.

142

tude et optimisation desrequtes

Axe 2

Les index normaux nont pas de spcificit de syntaxe, seuls les index locaux intgrent le mot cl LOCAL. Un index local sera dit "prfix" si les premires colonnes sont celles de la cl de partitionnement. Voici un exemple dindex local prfix:
create index IS_CLIENTS_PART_PAYSVILLE on CLIENTS_PART(pays,ville) local;

Les index locaux non prfixs prennent moins de place car ils ont lavantage de ne pas rpter la cl de partitionnement, ce qui est intressant pour des partitions monovaleurs. Sur les index locaux non prfixs, il faut parfois aider loptimiseur avec un hint pour quil utilise lindex.
MS SQL Server
La gestion des partitions est propose depuis SQL Server 2005, seul le partitionnement par intervalle est disponible. Il faut d'abord crer une fonction de partitionnement puis crer le schma de partitionnement et enfin assigner le schma de partitionnement la table. CREATE PARTITION FUNCTION myRangePF1 (int) AS RANGE LEFT FOR VALUES (1, 100, 1000); CREATE PARTITION SCHEME myRangePS1 AS PARTITION myRangePF1 TO (test1fg, test2fg, test3fg, test4fg); CREATE TABLE (. . . .) on myRangePS1(id);

MySQL
MySQL propose depuis la version5.1 la gestion des partitionnements Hash, List et Range mais pas le partitionnement composite ou par rfrence.

valuation

Nous allons valuer le partitionnement en utilisant la table cmd dun million denregistrements partitionne par intervalles sur la date de commande, comme montr prcdemment. La requte sera la suivante:
select count(*) from cmd where datecommande >=to_date('08/2008','MM/YYYY') and datecommande <to_date('09/2008','MM/YYYY')

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 143

Figure5.26 Trace d'excution sur table normale.

On constate ici que toute la table est parcourue.


Figure5.27 Trace d'excution sur la table partitionne.

On constate ici que seule la partition 2 est parcourue, do une chute des Consistent Gets et du temps dexcution.
Partitionnement conomique

Comme nous lavons dit, le partitionnement nest pas prsent dans toutes les ditions des produits. Pour avoir cette option, il faut souvent acqurir les versions haut de gamme et ce nest pas forcment compatible avec votre budget. Je vais vous prsenter une solution alternative ci-aprs, oriente base dcisionnelle. On peut certainement ladapter un usage OLTP, laide dun trigger INSTEAD OF, et simuler compltement le partitionnement, mais je ne vous le conseille pas.

144

tude et optimisation desrequtes

Axe 2

Une solution plus conomique consiste crer autant de tables quon aurait cr de partitions et adapter les requtes cette nouvelle organisation des donnes. Cela demandera sans doute pas mal de travail. Une faon de rduire ce travail est dagrger les tables dans une vue qui se nommera comme se nommait la table avant que vous ne la coupiez en morceaux. De cette faon, les requtes marcheront toujours. Cependant, si on ne fait rien de plus, le rsultat sera peu intressant, si ce nest de pouvoir profiter dun peu de paralllisme. En fait, pour que cela prsente un intrt, nous allons appliquer des contraintes de type CHECK dfinissant des intervalles sur les colonnes qui servent de pseudo-cls de partitionnement. Nous allons donc crerles objets suivants :
create table CMD_2005_2007 ( NOCMD NUMBER not null, NOCLIENT NUMBER, DATECOMMANDE DATE constraint CMD_2005_2007_CKPART check (DateCommande<TO_DATE('01/01/2008','DD/MM/YYYY')), ETATCOMMANDE CHAR(1), constraint PK_CMD_2005_2007 primary key (NOCMD) ); create table CMD_2008 ( NOCMD NUMBER not null, NOCLIENT NUMBER, DATECOMMANDE DATE constraint CMD_2008_CKPART check (DateCommande>=TO_DATE('01/01/2008','DD/MM/YYYY') and DateCommande<TO_DATE('01/01/2009','DD/MM/YYYY')), ETATCOMMANDE CHAR(1), constraint PK_CMD_2008 primary key (NOCMD) ); create table CMD_2009_MAX ( NOCMD NUMBER not null, NOCLIENT NUMBER, DATECOMMANDE DATE constraint CMD_2009_MAX_CKPART check (DateCommande>=TO_DATE('01/01/2009','DD/MM/YYYY')), ETATCOMMANDE CHAR(1), constraint PK_CMD_2009_MAX primary key (NOCMD) ); create view CMD_PART as select * from CMD_2005_2007 union all select * from CMD_2008 union all select * from CMD_2009_MAX;

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 145

Puis excuter la requte suivante :


select count(*) from cmd where datecommande >=to_date('08/2008','MM/YYYY') and datecommande <to_date('09/2008','MM/YYYY')

Figure5.28 Trace d'excution d'une requte sur une vue Union All de table avec des contraintes.

Des cots sont assigns linterrogation des tables cmd_2005_2007 et cmd_2009_ max, mais nous voyons dans la colonne Last_Output_Rows quaucune ligne nest rcupre. Cela vient de lajout dans le plan dexcution de prdicats faux NULL IS NOT NULL qui ont pour effet de "couper" ces branches dexcution. Nous retrouvons donc en interrogation les mmes performances quavec le partitionnement classique, linsertion des donnes, elle, nest pas gre.
MS SQL Server
Il est possible d'utiliser la mme astuce sous SQL Server, c'tait d'ailleurs la solution recommande avant la version2005, qui intgre le partitionnement.

MySQL
Pour cette opration, MySQL propose le moteur MERGE sur les tables MyISAM pour ce genre d'astuce mais l'absence de contrainte CHECK empchera d'utiliser la mme astuce. Le moteur MERGE permet de spcifier la table dans laquelle il faut faire les insertions.

146

tude et optimisation desrequtes

Axe 2

5.3.5

Les vues matrialises

Les vues matrialises (Materialized Views) sont des tables qui contiennent des donnes agrges ou jointes issues dautres tables. Elles sont dfinies par des requtes, comme les vues, mais stockent les donnes comme les tables. Le mcanisme de journalisation MATERIALIZED VIEW LOG permet de capturer les changements sur les donnes sources afin de faire des rafrachissements incrmentaux (Fast Refresh). Les vues matrialises peuvent tre rafrachies en temps rel, lors des COMMIT (obligatoirement FAST REFRESH), ou manuellement, la demande. Nous tudions cet objet en tant quobjet doptimisation, nous nous focaliserons donc sur le mode REFRESH ON COMMIT. Cependant, dans le cas de mises jour des tables par lot (batch), un rafrachissement manuel pourrait tre plus adapt. Mesurez bien les consquences en espace disque, en ressources CPU et en temps de rponse sur les tables sources lors de lutilisation de REFRESH ON COMMIT. En effet, chaque transaction a pour effet dactualiser de faon synchrone les donnes impactes des vues matrialises. Lutilisation des Materialized View et du Query Rewriting (voir ci-aprs) ncessite davoir les privilges suivants (mme si on est DBA):
GRANT GLOBAL QUERY REWRITE TO scott; GRANT CREATE MATERIALIZED VIEW to scott;

Un exemple de mise en uvre dune vue matrialise maintenue de faon incrmentale sur COmmiT est le suivant: nous commenons par crer les MATERIALIZED VIEW LOG. Ils permettent de capturer tous les changements sur les donnes sources afin de les rpercuter de faon incrmentale sur la vue matrialise sans avoir la recalculer entirement (il faut ny mettre que les champs impliqus dans la vue). Ensuite, nous crons la vue matrialise elle-mme. ReFReSH FAST ON COmmiT permet de prciser quelle sera maintenue de faon incrmentale chaque COmmiT et eNAbLe QUeRY ReWRiTe de signaler que cette vue peut tre utilise dans le cadre du Query Rewriting. Puisque notre requte effectue des agrgats de donnes, il y a quelques contraintes, entre autres, il doit imprativement y avoir une colonne count(*) et count(...) de chaque colonne concerne par une somme ou moyenne.
-- Cration de la journalisation sur les donnes sources CREATE MATERIALIZED VIEW LOG ON cmd WITH SEQUENCE ,ROWID(nocmd,noclient,datecommande,etatcommande) INCLUDING NEW VALUES; CREATE MATERIALIZED VIEW LOG ON cmd_lignes WITH SEQUENCE ,ROWID (NoCmd,Montant) INCLUDING NEW VALUES;

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 147

-- Cration de la vue CREATE MATERIALIZED VIEW MV_CMD PCTFREE 0 BUILD IMMEDIATE REFRESH FAST on commit with rowid ENABLE QUERY REWRITE AS select c.nocmd,c.noclient,c.datecommande,c.etatcommande ,sum(cl.montant) MontantCMD, COUNT(*) NbrItem ,count(Montant) NbrMontant from cmd c join cmd_lignes cl on c.nocmd=cl.nocmd group by c.nocmd,c.noclient,c.datecommande,c.etatcommande; -- Cration d'un index sur la vue create index is_MV_CMD_NoCmd on MV_CMD (NoCMD);

Une fois la vue matrialise cre, nous pouvons lutiliser plutt que les donnes sources dans nos requtes. Elle sera mise jour automatiquement chaque COMMIT.
Query Rewriting

Ce processus permet loptimiseur de rcrire de faon transparente des requtes crites sur les donnes sources dune vue matrialise pour utiliser celle-ci la place, si cela est plus performant. Si la vue matrialise est maintenue manuellement, toute modification sur une des tables sources invalidera le fonctionnement du Query Rewriting jusqu ce que la vue matrialise soit rafrachie. Par exemple, la requte suivante:
select sum(cl.montant) from cmd c join cmd_lignes cl on c.nocmd=cl.nocmd where c.NoCmd=18331

sera transforme de faon transparente par le Query Rewriting en:


select MontantCMD from MV_CMD where NoCmd=18331 ;

Comme on peut le voir sur ce plan dexcution, loptimiseur a dcid dutiliser les donnes agrges dans la vue matrialise pour rpondre la requte qui portait sur les donnes non agrges. On constate quil ny a plus daccs aux tables mentionnes dans la requte, lutilisation de la vue matrialise vite donc de faire la jointure. Si nous avions demand AVG(Montant), la requte aurait aussi t rcrite car avg(Montant)= sum(Montant)/ count(Montant) qui utilise deux oprandes prsents dans la vue matrialise.

148

tude et optimisation desrequtes

Axe 2

Figure5.29 Trace d'excution d'une requte rcrite par l'optimiseur.

MS SQL Server
Sous SQL Server, la mme fonctionnalit existe sous le nom de "vue indexe". Les noms des tables doivent imprativement tre prfixs par le schma qui les contient. Les agrgats ne doivent pas manipuler de valeurs nulles (d'o l'utilisation de ISNULL) et doivent contenir un COUNT_BIG(*). Il faut ensuite indexer cette vue pour la matrialiser. create view MV_CMD WITH SCHEMABINDING AS select c.nocmd,c.noclient,c.datecommande,c.etatcommande ,sum(isnull(cl.montant,0)) MontantCMD ,COUNT_BIG(*) NbrItem from dbo.cmd c join dbo.cmd_lignes cl on c.nocmd=cl.nocmd group by c.nocmd,c.noclient,c.datecommande,c.etatcommande; CREATE UNIQUE CLUSTERED INDEX IDX_MV_CMD ON dbo.MV_CMD(NoCmd);

MySQL
Il n'y a pas, sous MySQL, de fonctionnalit quivalente.

5.3.6

Reconstruction des index et des tables

Les mouvements lis au LMD (insert, update, delete) peuvent entraner une fragmentation des segments et ainsi aboutir des tables et des index "gruyres". Ce phnomne aura pour effet daugmenter inutilement le nombre de blocs manipuler et donc de rduire les performances. Pour les tables qui subissent beaucoup dajouts et de suppressions, ces oprations peuvent tre intressantes. Pour les autres, elles

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 149

seront gnralement inutiles car les mcanismes de base de rutilisation des espaces librs seront suffisamment efficaces. Les instructions de reconstruction permettent, avec certaines options (MOVE et REBUILD), de spcifier de nouvelles clauses de stockage et mme de changer de tablespace. Les reconstructions sont utiles aussi pour supprimer les effets des migrations de lignes (voir Chapitre 1, section 1.2.5, "Row Migration et Row Chaining"). Pour rorganiser les tables organises en tas, il faut avant tout autoriser les mouvements de lignes:
Alter table Clients Enable Row Movement;

Le dplacement dune table permet de la compacter en faisant une copie. Cette option est assez efficace mais, pendant lopration de copie, lespace requis est le double de lespace initial. Cette option permet aussi de spcifier de nouveaux paramtres de stockage:
Alter table <NomTable> move;

ATTENTION Cette instruction a pour effet particulirement significatif d'invalider tous les index. Il faudra donc les reconstruire, ce qui peut avoir un cot certain. Le script PL/SQL ci-aprs permet de reconstruire tous les index invalids:
begin for r in (SELECT 'alter index '||index_name||' rebuild' cmd from user_indexes where status='UNUSABLE') loop execute immediate r.cmd; end loop;

end;

Une variante est linstruction SHRINK TABLE qui ne marche que sur les segments situs dans des tablespaces en mode ASM (Automatic Storage Management) qui nutilisent pas dindex sur fonction:
Alter table clients shrink space;

150

tude et optimisation desrequtes

Axe 2

Pour rorganiser les index, deux options sont disponibles:


REBUILD.

Cest la reconstruction, opration efficace mais particulirement

coteuse:
Alter index <NomIndex> rebuild ;

COALESCE.

Solution plus lgre, elle fusionne les feuilles dindex conscutives, qui ont plus de 25% despace libre sans librer lespace des feuilles:

Alter index <NomIndex> coalesce ;

Impact sur la volumtrie et les performances

Afin dvaluer limpact des reconstructions, nous allons effectuer quelques oprations sur la table clients. Taille initiale. Table: 5120Ko; index cl primaire: 768 Ko; IS_CLIENTS_PAYS: 1024Ko. 1. Nous dupliquons la table sur elle-mme afin de doubler sa taille. Taille aprs doublement. Table: 10240Ko; index cl primaire: 2048Ko; IS_ CLIENTS_PAYS: 3072Ko. 2. Nous effaons la moiti des enregistrements. Taille aprs effacement. Table: 10240Ko; index cl primaire: 2048Ko; IS_ CLIENTS_PAYS: 3072Ko. Comme on le voit, lespace nest pas libr. 3. Nous effectuons un SHRINK sur la table et un REBUILD des index:
alter table CLIENTS shrink space; alter index PK_CLIENTS rebuild; alter index IS_CLIENTS_PAYS rebuild;

Taille aprs SHRiNK et RebUiLD. Table: 5120Ko; index cl primaire: 832Ko; IS_CLIENTS_PAYS: 1024Ko. Nous revenons la taille initiale. En termes despace occup, limpact est significatif. Ces oprations de maintenance peuvent tre importantes si des oprations volumineuses ont eu lieu sur les tables (ce qui narrive normalement pas tous les jours dans la plupart des applications). Voyons prsent limpact de la dfragmentation sur les performances.

Chapitre 5

Techniques doptimisation standard au niveau base de donnes 151

Table full scan. Avant: Consistent Gets: 26302; timing: 2,05s Aprs: Consistent Gets: 8608; timing: 1,33s Index full scan. Avant: Consistent Gets: 532; timing: 0,033s Aprs: Consistent Gets: 227; timing: 0,032s Index direct par recherche d'une valeur unique. Avant: Consistent Gets: 2; timing: 0,005s Aprs: Consistent Gets: 2; timing: 0,002s Limpact le plus significatif est sur le Table Full Scan qui lit tous les blocs de la table. On remarque que lindex, lui, saccommode plutt bien de leffet gruyre.

6
Techniques doptimisation standard des requtes
Loptimisation du SQL est un point trs dlicat car elle ncessite de pouvoir modifier lapplicatif en veillant ne pas introduire de bogues.

6.1

Rcriture des requtes

Lutilisation dobjets doptimisation est un lment qui, de manire gnrale, amliore les performances trs significativement. Cependant, la faon dcrire votre requte peut, elle aussi, dans certains cas, avoir un impact trs significatif. Ltape de transformation de requte (voir ci-aprs) est de plus en plus performante sur Oracle et SQL Server. Elle donne de trs bons rsultats, ce qui rend inutiles certaines recommandations dans le cas gnral. Cependant, sur MySQL ou sur des requtes compliques, o on peut considrer que le SGBDR narriverait pas faire certaines transformations tout seul, lutilisation des critures les plus performantes permettra damliorer les rsultats. Nous allons faire quelques comparaisons dcritures qui intgreront parfois un hint (voir Chapitre7, section7.1, "Utilisation des hints sous Oracle") afin dempcher certaines transformations. De faon gnrale, il faut privilgier les jointures. Le principe du modle relationnel tant que, lors de linterrogation, des jointures seront faites, on peut supposer que les diteurs de SGBDR ont concentr leurs efforts l-dessus. Cependant, sous MySQL avec le moteur MyISAM, les sous-requtes sont souvent plus performantes.

154

tude et optimisation desrequtes

Axe 2

6.1.1

Transformation de requtes

Ltape de transformation de requtes (Query Transformation) est partie intgrante du processus de traitement des requtes. Cest une des fonctions de loptimiseur CBO. Cette tape consiste transformer la requte soumise en une requte quivalente afin de la rendre plus performante. Cela va, au-del, de choisir le meilleur chemin dexcution. La transformation de requtes peut, par exemple, dcider de transformer une sous-requte en jointure. Vous pouvez influer sur cette tape au moyen des hints, mais cest rarement ncessaire. Les principales transformations effectues par le CBO sont:

Subquery unesting. Cette transformation consiste transformer des sousrequtes en jointures. Suppression dlments inutiles (certaines jointures, des colonnes slectionnes dans les sous-requtes). Predicate push. Cette transformation consiste dupliquer certains prdicats dans les sous-vues et les sous-requtes. View merging. Intgre lexcution des vues la requte principale. Query Rewriting. Utilisation des vues matrialises (voir Chapitre5, section5.3.5, "Les vues matrialises"). Or Expansion. Transforme des conditions OR en plusieurs requtes fusionnes par une sorte d"Union ALL".

Il ny a rien de particulier faire pour bnficier du Query Rewriting. Connatre lexistence de ce mcanisme vous aidera comprendre pourquoi il arrive parfois quun plan dexcution ne ressemble vraiment pas votre requte. Cette fonction est plus volue sous Oracle et SQL Server que sous MySQL.
INFO Au cours de ce chapitre, nous prsentons des variations de notation qui peuvent avoir un effet sur les performances. L'optimiseur tant assez performant, il transforme automatiquement les requtes soumises en la version la plus performante. Nous recourrons des hints pour empcher ces transformations afin de comparer les notations. L'utilisation de hint n'est nullement une recommandation, nous le mentionnons titre indicatif de faon que, si vous excutez ces requtes, vous puissiez reproduire les mmes rsultats que ceux prsents ici. Comme cela sera expliqu au Chapitre7, section7.1, "Utilisation des hints sous Oracle", il faut les utiliser en dernier recours et seulement en toute connaissance de cause.

Chapitre 6

Techniques doptimisation standard des requtes 155

6.1.2

IN versus jointure

Selon que lcriture dune requte se fasse avec une sous-requte et loprateur IN ou avec une jointure, limpact sera diffrent. Pour forcer le parcours des tables, et non seulement celui des index, nous utilisons dans la requte des champs non indexs (Quantit et Editeur).
Listing6.1: Requte utilisant une jointure
select sum(CL.quantite) from cmd_lignes CL,livres L where CL.nolivre = L.nolivre and L.editeur='Pearson'

Listing6.2: Requte utilisant une sous-requte


select sum(quantite) from cmd_lignes where nolivre in (select nolivre from livres where editeur='Pearson')

Nous allons tester ces requtes avec et sans index sur la colonne Nolivre de la table cmd_lignes.
create index IS_cmd_lignes on cmd_lignes(nolivre);

Sans index MyISAM Temps Key_read_requests InnoDB Temps Reads Jointure 12,89s 5242448 Sous-requte 13,53s 5243442 0,01s 158

Avec index Jointure Sous-requte 13,53s 5243442 Sous-requte 13,51s 2606480

Jointure 3,48s 3700

InnoDB crant automatiquement un index dans la table fille de la Foreign Key, il y a forcement un index sur la colonne Nolivre de la table cmd_lignes. La cration de lindex est donc sans effets.
Sans index Oracle Temps Consistent Gets Jointure 6,15s 8336 Sous-requte 8,75s 4891735 0,01s 807 Avec index Jointure Sous-requte 0,60s 12175

156

tude et optimisation desrequtes

Axe 2

Pour viter la transformation de la version utilisant une sous-requte en version jointure par le mcanisme de transformation de requte, nous devons utiliser le hint /*+no_unnest*/ et pour forcer lusage de lindex, le hint /*+ index (CL IS_cmd_ lignes)*/. Si nous ne mettons aucun hint, loptimiseur choisit systmatiquement de faire une jointure sans utiliser lindex.
Sans index MS SQL Server Temps Estimated Cost Jointure 0,625s 35,27 Avec index Sous-requte 0,046s 60,44

Afin de comparer les rsultats entre les bases, nous dsactivons le paralllisme sous SQL Server au moyen du code option (MAXDOP 1). Nous navons pas trouv de combinaisons de hints permettant de forcer lutilisation dune sous-requte tant quil ny a pas dindex. Une fois lindex plac, nous avons d contraindre son utilisation avec le hint WITH (INDEX(IS_CMD_LIGNES)). En revanche, nous navons pas russi forcer une jointure pertinente utilisant cet index. Conclusion : Oracle et SQL Server, grce leur capacit de transformation de requte volue, excutent les requtes de la mme faon quelle que soit la notation employe, si aucun hint nest utilis. Lorsque la transformation nest pas effectue, on constate que la solution base de jointure est gnralement plus performante. Au cas o le SGBDR narriverait pas faire la transformation, il est prfrable de prendre lhabitude dcrire des jointures plutt que des sous-requtes.
6.1.3 Sous-requtes versus anti-jointures

Une anti-jointure est une jointure ouverte pour laquelle vous ne slectionnez que les valeurs non jointes. Les requtes ci-dessous, permettent de slectionner les livres qui nont jamais t commands.
Listing6.3: Version Exists
select * from livres L where not exists (select 1 from cmd_lignes CL where CL.NOLIVRE=L.NOLIVRE)

Chapitre 6

Techniques doptimisation standard des requtes 157

Listing6.4: Version anti-jointure


select L.* from livres L left outer join cmd_lignes CL on CL.NOLIVRE=L.NOLIVRE where cl.nolivre is null

Nous allons tester ces requtes avec et sans index sur la colonne Nolivre de la table cmd_lignes.
create index IS_cmd_lignes on cmd_lignes(nolivre);

Sans index MyISAM Temps Key_read_requests Anti-jointure 10,11s 29850364 Sous-requte 10,11s 29850364

Avec index Anti-jointure 0,02s 2974 Sous-requte 0,02s 2974

L'anti-jointure est transforme en sous-requte.


InnoDB Temps Reads Anti-jointure 24,31s 2976 Sous-requte 25,34s 5948

InnoDB crant automatiquement un index dans la table fille de la Foreign Key, il y a forcment un index sur la colonne Nolivre de la table cmd_lignes. La cration de lindex est donc sans effets.
Sans index Oracle Temps Consistent Gets Anti-jointure 0,340s 6976 Sous-requte 2,282s 113419 0,375s 5522 Avec index Anti-jointure Sous-requte 0,031s 8909

Nous utilisons le hint /*+NO_QUERY_TRANSFORMATION*/ pour empcher la transformation de la sous-requte en anti-jointure.


Sans index MS SQL Server Temps Estimated Cost Anti-jointure 2,437s 47,49 Avec index Anti-jointure 0,079s 0,54

158

tude et optimisation desrequtes

Axe 2

Quelle que soit la notation utilise, la requte est transforme en anti-jointure. Les rsultats sont mitigs sous Oracle. Malheureusement, ltape de transformation de requte nopte pas toujours pour la meilleure option. Loptimiseur choisit systmatiquement lanti-jointure qui est, en effet, gnralement la meilleure option. Ici, la table livre est bien plus petite que la table cmd_lignes, dans ce cas, si un index est prsent sur la table fille de la Nested Loop, la solution utilisant une sous-requte est la meilleure. Il faut donc utiliser un hint pour forcer ce choix. Sur les autres SGBDR, ltape de transformation ne laisse pas le choix, les deux critures se valent.
6.1.4 Exists versus Count

Les requtes effectuant un test dexistence sont quivalentes un comptage gal 0.


Listing6.5: Version Exists
select * from livres L where not exists (select 1 from cmd_lignes CL where CL.NOLIVRE=L.NOLIVRE)

Listing6.6: Version 0=count(*)


select * from livres L where 0 = (select count(*) from cmd_lignes CL where CL.NOLIVRE=L.NOLIVRE)

Nous allons tester ces requtes avec un index sur la colonne Nolivre de la table cmd_lignes.
create index IS_cmd_lignes on cmd_lignes(nolivre);

MyISAM Temps Key_read_requests InnoDB Temps Reads Oracle Temps Consistent Gets

Exists 0,020s 11915 Exists 22,940s 8900 Exists 0,031s 8909

Count 1,110s 166782 Count 29,590s 2606477 Count 0,031s 8909

Chapitre 6

Techniques doptimisation standard des requtes 159

MS SQL Server Temps

Exists 0,062s

Count 0,062s

Oracle et SQL Server considrent ces deux critures quivalentes, alors que MySQL les voit bien diffrentes. On suppose que dans la version utilisant COUNT(*), il dnombre toutes les occurrences pour tester lgalit 0, alors que la version utilisant EXISTS sarrte la premire occurrence trouve.
6.1.5 Exists versus IN
IN

Une sous-requte utilisant loprateur requte utilisant loprateur EXISTS.

peut facilement tre convertie en sous-

Nous allons tester ces requtes avec un index sur la colonne Nolivre de la table cmd_lignes.
create index IS_cmd_lignes on cmd_lignes(nolivre);

Listing6.7: Version sous-requte IN


select sum(quantite) from cmd_lignes where nolivre in (select nolivre from livres where editeur='Pearson')

Listing6.8: Version sous-requte Exists


select sum(quantite) from cmd_lignes cl where exists (select nolivre from livres L where editeur='Pearson' and CL.nolivre=L.nolivre )

MyISAM Temps Key_read_requests InnoDB Temps Reads Oracle Temps Consistent Gets

In 14,010s 5243442 In 7,420s 2606480 In 8,594s 4891735

Exists 15,340s 5242448 Exists 8,200s 5212684 Exists 8,594s 4891735 Forage index 4,234s 2462067

160

tude et optimisation desrequtes

Axe 2

Loptimiseur Oracle dcide de ne pas utiliser lindex. Si nous forons son usage laide du hint /*+ index(cl is_cmd_lignes)*/, nous notons une amlioration des performances. Nous utilisons le hint /*+NO_QUERY_TRANSFORMATION*/ pour empcher la transformation des sous-requtes en anti-jointures qui ont un temps de rponse de lordre 0,34seconde.
MS SQL Server Temps In ou Exists 0,625s Forage index 0,046s
WITH

Comme sous Oracle, nous devons forcer lutilisation de lindex avec le hint
(INDEX(IS_CMD_LIGNES)).

Oracle et SQL Server considrent ces deux critures quivalentes, alors que MySQL les voit diffrentes, lavantage tant loprateur IN sur les deux moteurs de MySQL.
6.1.6 Clause Exists * versus constante

On enseigne, depuis des annes, que lorsquon emploie des sous-requtes corrles utilisant loprateur EXISTS, il faut retourner une constante (numrique ou texte) dans la clause SELECT de la sous-requte. Est-ce seulement pour des raisons de clart ou aussi de performances?
Listing6.9: Version Exists constante
select * from livres L where not exists (select 1 from cmd_lignes CL where CL.NOLIVRE=L.NOLIVRE);

Listing6.10: Version Exists *


select * from livres L where not exists (select * from cmd_lignes CL where CL.NOLIVRE=L.NOLIVRE);

Nous ne documentons pas le dtail des rsultats. On constate que les colonnes retournes dans la sous-requte nont aucun impact sur les performances, alors quelles en avaient sur danciennes versions dOracle. Cette pratique de mettre une constante garde cependant tout son sens du point de vue de la comprhension. Parfois, certains dveloppeurs mettent ici un champ particulier laissant ainsi croire quil y aurait une sorte de lien possible avec ce champ.

Chapitre 6

Techniques doptimisation standard des requtes 161

6.1.7

Expressions sous requtes

Listing6.11: Requte utilisant une jointure


select c.nocmd,datecommande ,sum(montant) Total from cmd c,cmd_lignes cl where cl.nocmd=c.nocmd and datecommande<to_ date('2004-04-18','yyyy-mm-dd') group by c.nocmd, datecommande

Listing6.12: Requte utilisant une expression sous-requte


select nocmd,datecommande ,(select sum(montant) from cmd_lignes where nocmd=c.nocmd) Total from cmd c where datecommande<to_date('2004-04-18','yyyy-mm-dd')

Nous choisissons ici une requte qui empche dappliquer le prdicat de la table cmd directement la table cmd_lignes et qui ne retourne que 173lignes. En changeant la date, nous testons une autre version qui ramne beaucoup plus de lignes (132141).
Petite requte MyISAM Temps Reads Jointure 5,890s 4873397 Petite requte InnoDB Temps Reads Jointure 0,670s 1001449 Expression sous-requte 0,670s 1000175 Expression sous-requte 0,060s 3316 Expression sous-requte 0,109s Expression sous-requte 0,160s 736 Grosse requte Jointure 6,810s 4873397 Expression sous-requte 1,950s 564513 Expression sous-requte 4,030s 1632143 Expression sous-requte 1,51s 117464 Expression sous-requte 0,953s

Grosse requte Jointure 3,580s 2264285

Petite requte Oracle Temps Consistent Gets Jointure 0,390s 11490

Grosse requte Jointure 1,48s 11490

Petite requte MS SQL Server Temps Jointure 0,125s

Grosse requte Jointure 0,812s

162

tude et optimisation desrequtes

Axe 2

Avec des requtes ramenant peu de lignes, l'avantage est aux expressions sousrequtes. Avec des requtes ramenant beaucoup de lignes, l'avantage passe la version jointure, sauf pour le moteur MyISAM qui a l'air plus l'aise avec l'utilisation systmatique d'expressions sous-requtes. Seul l'optimiseur de SQL Server adapte automatiquement son plan d'excution la solution la plus efficace, indpendamment de l'criture. Nous avons donc utilis les hints loop join et merge join pour effectuer ces tests.
6.1.8 Agrgats: Having versus Where

Quand cest possible, les conditions doivent tre places dans la clause WHERE plutt que dans la clause HAVING qui est value aprs les oprations dagrgation. Cela permet de profiter dventuels index et rduit le volume traiter durant lopration dagrgation.
Listing6.13: Requte utilisant Having (incorrecte)
select pays,ville,count(*) from clients t group by pays,ville having pays='France'

Listing6.14: Requte utilisant Where


select pays,ville,count(*) from clients t where t.pays='France' group by pays,ville

MyISAM Temps Reads InnoDB Temps Reads Oracle Temps Consistent Gets MS SQL Server Temps

Having 0,080s 91109 Having 0,090s 91132 Having 0,047s 624 Having 0,046s

Where 0,030s 45950 Where 0,050s 45960 Where 0,015s 624 Where 0,046s

Chapitre 6

Techniques doptimisation standard des requtes 163

Dans le plan dexcution de SQL Server, on voit quil dplace le prdicat de la clause HAVING la clause WHERE, il ny a donc pas dimpact li lcriture. Par contre, sur tous les autres SGBDR, limpact est notable et dautant plus que la slectivit du prdicat est forte.

6.2
6.2.1

Bonnes et mauvaises pratiques


Mlange des types

Le mlange des types peut causer des grosses chutes de performances en disqualifiant des index cause de conversions (cast) ncessaires. Dans la pratique, cest rarement une source de problme de performances mais plutt une source de problme dexcution (message derreur) car le SGBDR fait les conversions adquates. Cependant, une bonne pratique est de veiller faire explicitement les conversions adaptes.
6.2.2 Fonctions et expressions sur index

Lutilisation de fonctions (y compris de conversion) ou dexpressions sur des colonnes indexes a pour effet de disqualifier les index.
select * from cmd_lignes where 'C' || nocmd='C114826'

Cette requte entrane un parcours complet de la table alors quil serait pertinent dutiliser lindex sur la colonne Nocmd. Sil nest pas possible de se passer de lexpression C + nocmd, les index sur fonction (voir Chapitre5, section5.2.2, "Index sur fonction") peuvent apporter une solution ce type de problme. Ci-aprs, les deux options possibles qui permettent cette requte de tirer profit de lindex sur le champ Nocmd:
select * from cmd_lignes where nocmd=114826

ou:
Create Index IS_CMD_LIGNE_CNOCMD on CMD_LIGNES('C' || nocmd);

164

tude et optimisation desrequtes

Axe 2

6.2.3

Impact de l'oprateur <> sur les index

Loprateur <> et ses quivalents!= et ^= ont un impact notable sur les index car il ne les utilise pas. Illustrons ce comportement sur la requte suivante qui recherche la date de la plus ancienne commande qui nest pas clture (Etatcommande <> C):
select min(datecommande) from cmd where etatcommande <>'C'

Nous avons pralablement cr un index et forc le calcul dun histogramme sur la colonne Etatcommande:
create index is_cmd_etat on cmd(etatcommande); execute dbms_stats.gather_table_stats(user,'cmd',cascade => true ,estimate_percent =>100,method_opt => 'for all columns size 100');

La distribution de la colonne Etatcommande est la suivante:


Etatcommande A C I Nombre denregistrements 240 994700 5060

Cette requte traite moins de 1% des lignes et profiterait donc dun index plac sur la colonne Etatcommande, mais la prsence de loprateur <> lempche. Une solution permettant de contourner ce problme est de transformer cette requte. Cela se fait soit par des galits:
select min(datecommande) from cmd where etatcommande in ('A','I')

soit par des intervalles excluant la valeur:


select min(datecommande) from cmd where etatcommande >'C' or etatcommande <'C'

Ces deux solutions utilisent lindex prsent sur la colonne Etatcommande et les rsultats sont sans appel. Le temps dexcution passe de 125 ms 15 ms et les Consistent Gets passent de 3194 58.
6.2.4 Rutilisation de vue

Parfois, une vue existante peut tre une bonne base pour faire une requte. Dans ce cas, il faut vrifier que cette vue ne fait pas trop de travail inutile pour le besoin de la requte que vous souhaitez crire. Assurez-vous quil ny a pas plus de tables en jeu que celles que vous auriez utilises si vous naviez pas choisi la vue. Par exemple,

Chapitre 6

Techniques doptimisation standard des requtes 165

vous souhaitez calculer le chiffre daffaires journalier et vous disposez de la vue suivante:
create view V_CA_JOURNALIER_PAYS as Select cmd.datecommande,cli.pays, sum(cl.montant) CA from cmd join cmd_lignes cl on cmd.nocmd=cl.nocmd join clients cli on cmd.noclient=cli.noclient group by cmd.datecommande,cli.pays

Vous trouvez donc que la solution la plus simple est de partir de cette vue en crivant la requte suivante:
select datecommande,sum(CA) from V_CA_JOURNALIER_PAYS group by datecommande

Cette solution est certes pratique mais elle a linconvnient de faire une jointure avec la table clients qui nest pas du tout ncessaire pour rpondre votre requte. Lecot de votre requte passe ainsi de 7290 20136.
6.2.5 Utilisation de tables temporaires

Pour certaines requtes compliques (mettant en uvre de nombreuses tables), il peut tre pertinent de travailler avec des tables temporaires. Ce choix est intressant si le contenu de ces tables est interrog plusieurs fois afin de compenser le cot de leur cration. Ces tables pourront tre indexes, de prfrence aprs linsertion des donnes. Sous Oracle, vous pouvez spcifier de ne pas tracer les oprations dans ce genre de tables en utilisant la clause NOLOGGING lors de leur cration.
Create table xxx ( . . . ) NOLOGGING;

6.2.6

Utilisation abusive de SELECT *

Lutilisation de loprateur * dans la clause SELECT ramne tous les champs. Certains dveloppeurs trouvent cela particulirement pratique mais ne mesurent pas forcment les consquences que cela peut avoir. Si vous avez besoin de ramener tous les champs de la table, il ny a rien dire, Select * From LaTable est tout fait correct. Cependant, il y a de nombreux cas o * est utilis alors que seuls certains champs sont ncessaires. Dans ce cas, on subit inutilement:

une augmentation du volume transfr entre le client et le serveur;

166

tude et optimisation desrequtes

Axe 2

une augmentation du volume mmoire ncessaire par le client et le serveur; une augmentation des E/S disque du serveur sil y a des champs stocks dans des segments spars (LOB, Text,etc.).

Prenez lhabitude de ne ramener que les donnes dont vous avez besoin en listant les champs dans la clause SELECT. Il est frquent de trouver dans des standards de codage linterdiction de loprateur*. La raison est que, si au moment du codage on a besoin de tous les champs, ce ne sera peut-tre plus le cas si un champ est ajout en phase de maintenance.
6.2.7 Suppression des tris inutiles

Les tris sont coteux, il faut donc sassurer quils sont ncessaires. Dans la requte ci-aprs, sous Oracle, lajout du tri par Nom fait passer le cot de 171 1179 et double le temps dexcution.
select * from clients order by nom

Si le mot cl DISTINCT est prsent, les consquences sont similaires car il ncessite un tri.
6.2.8 Utilisation raisonne des oprations ensemblistes

Les oprations sur les ensembles (UNION, MINUS, INTERSECT) sont assez coteuses et ne sont jamais transformes automatiquement par loptimiseur. Il faut y recourir seulement quand cest la solution la plus adapte. Les oprations INTERSECT peuvent souvent tre remplaces par une jointure et les oprations MINUS, par une anti-jointure ou un NOT IN. La suppression des oprations ensemblistes permettra dliminer des tris intermdiaires et davoir un plan dexcution plus efficace. Les oprations de type UNION sont souvent plus dlicates supprimer. Les transformations de lopration INTERSECT sont illustres travers la requte suivante qui recherche les clients qui ont achet le livre 1306 et qui ont pass moins de 50commandes.
Listing6.15: Version utilisant INTERSECT
select distinct c.noclient,c.nom,c.prenom,c.pays from cmd_lignes cl join cmd on cl.nocmd=cmd.nocmd join clients c on cmd.noclient=c.noclient where cl.nolivre=1306 intersect

Chapitre 6

Techniques doptimisation standard des requtes 167

select c.noclient,c.nom,c.prenom,c.pays from cmd join clients c on cmd.noclient=c.noclient group by c.noclient,c.nom,c.prenom,c.pays having count(*)<50

Temps dexcution: 0,703s, Consistent Gets: 6721, Cost: 10312


Listing6.16: Version utilisant une jointure
select A.* from (select distinct c.noclient,c.nom,c.prenom,c.pays from cmd_lignes cl join cmd on cl.nocmd=cmd.nocmd join clients c on cmd.noclient=c.noclient where cl.nolivre=1306 ) A , (select c.noclient,c.nom,c.prenom,c.pays from cmd join clients c on cmd.noclient=c.noclient group by c.noclient,c.nom,c.prenom,c.pays having count(*)<50 ) B where a.noclient=b.noclient

Temps dexcution: 0,703s, Consistent Gets: 6721, Cost: 6945

Suite cette transformation, le gain nest pas forcment significatif, mais le fait dutiliser une jointure permet de factoriser les jointures avec la table clients prsente dans chacune des sous-requtes (voir Listing 6.17). Cette factorisation peut amliorer les performances surtout si les ensembles retourns par les sous-requtes sont gros.
Listing6.17: Version factorisant la jointure de la table clients
select c.noclient,c.nom,c.prenom,c.pays from (select distinct cmd.noclient from cmd_lignes cl join cmd on cl.nocmd=cmd.nocmd where cl.nolivre=1306 ) A , (select noclient from cmd group by noclient having count(*)<50 ) B , clients c where a.noclient=b.noclient and a.noclient=c.noclient

Temps dexcution: 0,531s, Consistent Gets: 7050, Cost: 2828

Illustrons une transformation de lopration MINUS sur la requte suivante qui recherche les clients qui nont pas achet le livre 3307 et qui ont pass plus de 60commandes.

168

tude et optimisation desrequtes

Axe 2

Listing6.18: Version utilisant MINUS


select c.noclient,c.nom,c.prenom,c.pays from cmd join clients c on cmd.noclient=c.noclient group by c.noclient,c.nom,c.prenom,c.pays having count(*)>60 MINUS select distinct c.noclient,c.nom,c.prenom,c.pays from cmd_lignes cl join cmd on cl.nocmd=cmd.nocmd join clients c on cmd.noclient=c.noclient where cl.nolivre=3307

Temps dexcution: 0,672s, Consistent Gets: 7572, Cost: 10312


Listing6.19: Version utilisant une anti-jointure
select A.* from (select c.noclient,c.nom,c.prenom,c.pays from cmd join clients c on cmd.noclient=c.noclient group by c.noclient,c.nom,c.prenom,c.pays having count(*)>60 ) A left outer join (select distinct c.noclient,c.nom,c.prenom,c.pays from cmd_lignes cl join cmd on cl.nocmd=cmd.nocmd join clients c on cmd.noclient=c.noclient where cl.nolivre=3307 ) B on a.noclient=b.noclient where b.noclient is null

Temps dexcution: 0,672s, Consistent Gets: 7572, Cost: 6945

Tout comme avec INTERSECT, le fait dutiliser une jointure nous permet de factoriser les jointures avec la table clients prsente dans chacune des sous-requtes.
Listing6.20: Version utilisant une anti-jointure factorisant la jointure de la table clients
select c.noclient,c.nom,c.prenom,c.pays from (select noclient from cmd group by noclient having count(*)>60 ) A left outer join (select noclient from cmd_lignes cl join cmd on cl.nocmd=cmd.nocmd where cl.nolivre=3307 ) B on a.noclient=b.noclient , clients c where A.noclient=c.noclient

Temps dexcution: 0,516s, Consistent Gets: 7899, Cost: 2827

Chapitre 6

Techniques doptimisation standard des requtes 169

6.2.9

Union versus Union ALL

Les oprateurs UNION et UNION ALL sont trs proches. La seule diffrence est que, si une donne est prsente dans les deux ensembles, elle napparatra quune fois dans le cas de loprateur UNION. Mais il y a un pige: si la donne apparat deux fois dans un des ensembles, elle napparatra aussi quune seule fois dans lensemble rsultat. On peut donc en dduire que
UNION = DISTINCT UNION ALL

Comme nous lavons vu au paragraphe prcdent, ce provoque lexcution dun tri. Loprateur connu.
Figure6.1 Plan d'excution utilisant UNION.
UNION

DISTINCT

a un cot car il qui est moins

est souvent utilis tort la place dUNION

ALL,

170

tude et optimisation desrequtes

Axe 2

Figure6.2 Plan d'excution utilisant UNION ALL.

Nous constatons dans ces traces dexcution que le cot, les Consistent Gets et le temps dexcution augmentent de faon significative. On voit aussi quil y a un tri de plus. Plus lensemble rsultat est gros, plus limpact sera fort.
6.2.10 Count(*) versus count(colonne)

La fonction COUNT a pour objet de compter les valeurs non nulles dune colonne, mais elle est souvent utilise pour compter le nombre denregistrements. Dans ce cas, la notation COUNT(*) est prconise. Cependant, par mconnaissance ou par habitude, certaines personnes continuent utiliser COUNT(colonne). Lutilisation de COUNT(*) permet loptimiseur de ne pas accder lenregistrement entier sil nen a pas besoin pour rpondre la requte car il peut le faire avec des index. La requte ci-aprs a un cot de 27 et naccde qu lindex de la cl primaire:
select count(*) from clients

Alors que cette requte, qui retourne le mme rsultat si on considre que les noms sont remplis, provoque un parcours complet de la table et a un cot de 171:
select count(nom) from clients

Chapitre 6

Techniques doptimisation standard des requtes 171

Cependant, si la colonne est note obligatoire (NOT NULL), alors loptimiseur convertit automatiquement COUNT(colonne) en COUNT(*).
6.2.11 Rduction du nombre de parcours des donnes

Plutt que parcourir nfois un ensemble de donnes pour rpondre nquestions, on essaiera de ne le parcourir quune fois en rpondant simultanment aux nquestions. Linstruction CASE sera utile cette fin puisquelle permet davoir une syntaxe proche des clauses WHERE.
Listing6.21: Requte provoquant trois parcours des donnes
SELECT '<2000' categ,COUNT (*) FROM cmd_lignes WHERE montant < 2000 union all SELECT '2000-4000' categ,COUNT (*) FROM cmd_lignes WHERE montant BETWEEN 2000 AND 4000 union all SELECT '>4000' categ,COUNT (*) FROM cmd_lignes WHERE montant >4000 ; CATEG COUNT(*) --------- ---------<2000 2604322 2000-4000 2146 >4000 9

Listing6.22: Requte ne parcourant qu'une seule fois les donnes


SELECT count (CASE WHEN montant < 2000 THEN 1 END) nbrinf2k, count (CASE WHEN montant BETWEEN 2000 AND 4000 THEN 1 END) nbr2k4k, count (CASE WHEN montant > 4000 THEN 1 END) nbrsup4k FROM cmd_lignes; NBRINF2K NBR2K4K NBRSUP4K ---------- ---------- ---------2604322 2146 9

Note: la fonction COUNT ne compte que les valeurs non nulles et labsence de clause ELSE quivaut ELSE NULL. Nous aurions obtenu le mme rsultat avec la fonction SUM, mais nous avons un meilleur temps de rponse en comptant les valeurs non nulles. La seconde requte ne demande quun seul parcours de la table au lieu de trois pour la premire. Elle sera ainsi gnralement plus performante. Si la table est grande et ncessite des accs disques, lcart sera dautant plus net. Si la table peut tenir en mmoire, lcart sera moindre, voire invers.

172

tude et optimisation desrequtes

Axe 2

Dans lexemple que nous prsentons ici, la table tient en mmoire. De ce fait, sous Oracle et SQL Server le gain nest pas du tout significatif; par contre, sous MySQL lcart est significatif.
6.2.12 LMD et cls trangres

Les contraintes dintgrit rfrentielle implmentes par des cls trangres (Foreign Key) sont contrles dans le sens fils parent, lors de linsertion de donnes dans les tables filles. Lors des UPDATE de cl ou des DELETE dans la table rfrence (table parente de la relation), le SGBDR contrle dans les tables filles si des enregistrements existent, soit pour interdire lopration, soit pour propager leffacement ou la mise jour si les options ON CASCADE DELETE ou ON CASCADE UPDATE sont actives. Dans les deux cas, pour chaque cl impacte, le SGBDR effectue une requte dans la table fille. La table parente est, par conception, systmatiquement indexe. Ainsi, le contrle de la prsence de la cl dans la table rfrence lors de linsertion dune donne dans la table fille sera performant, mme si, sur de gros volumes, le cot peut devenir significatif par rapport labsence de contrainte de type cl trangre. Par contre, sur les tables filles, les champs sont moins souvent indexs, ce qui peut causer de gros problmes de performances en cas dopration portant sur des volumes importants. Dans notre base exemple, imaginons que la suppression dun client provoque leffacement de ses commandes et des lignes de commandes associes. Labsence dindex sur les colonnes filles pourrait causer une norme chute des performances en cas de suppression de centaines de clients. On note que, par conception, sur les relations dpendantes (comme ici entre cmd et cmd_lignes), la cl de la table parente se retrouve dans la cl de la table fille et est donc indexe. Lors dun test que nous avons effectu, nous avons constat un ratio de 125 (5secondes contre 650secondes); par ailleurs, nous avons dj eu loccasion de voir chez un client un DELETE durer deux heures au lieu de quelques secondes sur des grandes tables. Attention, le cot des oprations impliques par du LMD nest pas affich, ni valu dans le plan dexcution des instructions LMD. Une bonne pratique consiste indexer les colonnes filles des relations 1N, surtout si les parents sont mouvements. Ces index sont frquemment pertinents pour laspect interrogation des donnes.

Chapitre 6

Techniques doptimisation standard des requtes 173

6.2.13 Suppression temporaire des index et des CIR

Pour certaines oprations de chargement massif de donnes, il peut parfois tre pertinent de supprimer les index et les CIR (principalement les Foreign Key et les cls primaires) et de les rcrer une fois lopration termine. Cette solution permet dconomiser la rorganisation dynamique de lindex et damliorer le temps ncessaire au contrle des contraintes. Cependant, elle nest pas toujours intressante et doit donc tre value au cas par cas (comme toute solution visant amliorer les performances). En cas de dsactivation de contraintes, il faudra veiller charger des donnes qui les respectent. Sinon, il ne sera pas possible de les ractiver par la suite, ce qui pourra poser des problmes de qualit des donnes. Si les cls primaires ne peuvent pas tre recres cause de la prsence de doublons de cls, les index normalement associs aux cls ne seront pas crs non plus, ce qui aboutira une probable chute des performances.
6.2.14 Truncate versus Delete

La commande TRUNCATE permet de vider entirement le contenu dune table. Elle est donc fonctionnellement quivalente la commande DELETE sans clause WHERE. Elle fait partie des commandes LDD (langage de dfinition des donnes) et travaille au niveau des structures de donnes plutt quau niveau des enregistrements. Elle est ainsi bien plus performante car elle ne ncessite pas lusage des fonctionnalits de journalisation et des transactions. Cependant, faire partie des commandes LDD lui impose quelques limites et induit quelques consquences:

Les mmes privilges que pour faire un DROP de la table sont requis (le privilge DELETE ne suffit pas). La table tronque ne peut tre rfrence daucune Foreign Key. Il est impossible de faire un implicite).
ROLLBACK

(cela provoque dailleurs un

COMMIT

6.2.15 Impacts des verrous et des transactions

Le fait de pouvoir travailler plusieurs personnes sur une mme base grant les notions de transactions isoles a des consquences techniques normes du point de

174

tude et optimisation desrequtes

Axe 2

vue du SGBDR (Oracle, SQL Server, moteur InnoDB de MySQL). Nous pourrions consacrer un chapitre entier ce sujet, mais cette section rsume les points cls. Par exemple, lors de la modification dun enregistrement:

Si un ROLLBACK est excut, il faut remettre lancienne valeur. Tant quun COMMIT nest pas excut: les autres utilisateurs voient les anciennes donnes; si un autre utilisateur essaie de modifier les donnes, l'opration provoquera une erreur ou sera bloque grce la gestion des verrous.

Tout cela est gr grce des mcanismes de verrouillage et de gestion des versions de lignes (MVCC, Multi Version Concurrency Control), qui sont trs volus, ce qui a donc un cot en termes de ressources. La norme SQL propose quatre niveaux disolation qui ont des impacts diffrents sur les performances:

Read Uncommitted. Ne gre pas les versions de lignes. On voit les dernires oprations mme si elles ne sont pas valides, on parle alors de "lectures sales" (dirty read). Ce mode nest pas recommand, mais cest le seul mode de travail connu des SGBDR ne grant pas les transactions (moteur MyISAM de MySQL par exemple). Read Committed. On ne voit que ce qui est valid. Cest le mode de fonctionnement par dfaut des SGBDR grant les transactions. Repeatable Read. Si une mme transaction rexcute une requte, elle verra toujours les mmes donnes, mme si des changements ont t valids; cependant, de nouveaux enregistrements valids pourront apparatre. Serializable. Si une mme transaction rexcute une requte, elle verra toujours les mmes donnes.

Oracle gre seulement les modes Read Committed et Serializable au moyen des instructions suivantes:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

Oracle propose aussi une variante plus conomique en ressource de Serializable en empchant les modifications depuis la transaction courante laide de linstruction:
SET TRANSACTION ISOLATION LEVEL READ ONLY;

Chapitre 6

Techniques doptimisation standard des requtes 175

Sous MySQL, avec le moteur InnoDB les quatre niveaux sont disponibles, mais en fait Repeatable Read et Serializable sont quivalents. SQL Server propose et implmente les quatre niveaux. De faon gnrale, pour viter des impacts ngatifs sur les performances lies ces mcanismes, appliquez les rgles suivantes:

Faites des transactions courtes. Si vous modifiez de gros volumes de donnes, essayez de dcomposer lopration en plusieurs transactions. Faites souvent des COMMIT. Ne verrouillez pas les donnes outrance.

Par ailleurs, si vous ne craignez pas de mauvaise surprise avec les critures non valides, vous pouvez utiliser, lorsque cela est disponible, Read Uncommited, le niveau disolation minimal. Ce niveau peut afficher des incohrences dans les donnes si les transactions font des modifications dans plusieurs tables simultanment. Il est cependant adapt de nombreuses requtes dans de nombreux environnements. Ilmrite dtre tudi sil vous apporte des gains significatifs.
6.2.16 Optimisation du COMMIT

Linstruction COMMIT permet de terminer une transaction et dans de nombreux cas ne ncessite pas de prcautions particulires. Nanmoins, dans des traitements par lot (batch) qui manipulent de gros volumes, quelques optimisations peuvent tre apportes. En effet, lappel de COMMIT valide la transaction et la rend ainsi durable (cest le D dACID, voir encadr Info ci-aprs). Pour cela, la transaction est crite dans le fichier journal de transactions provoquant une E/S. Une premire piste doptimisation consiste jouer sur la frquence des COMMIT. En effet, lorsque vous modifiez un million denregistrements, vous pouvez dcider de faire un COMMIT:

chaque ligne modifie; la fin du traitement; de faon priodique.

Si vous avez le choix (ce qui nest pas toujours le cas), il est prfrable de faire des COMMIT rguliers portant sur des volumes de quelques dizaines quelques centaines

176

tude et optimisation desrequtes

Axe 2

denregistrements. Un COMMIT chaque ligne modifie est coteux de mme quun COMMIT portant sur un gros volume de donnes. Une seconde piste consiste prendre quelques liberts avec laspect durable de la transaction, en laissant les critures disque se faire de faon asynchrone au COMMIT et non pas de faon bloquante. Cest possible avec les options NOWAIT et BATCH de linstruction COMMIT. Il ne faut pas utiliser ces options si la criticit des donnes ne permet pas de prendre de libert avec laspect ACID de la transaction.
INFO Une transaction doit tre ACID, c'est--dire rpondre aux caractristiques suivantes: Atomique. La totalit ou aucune des oprations composant la transaction doit tre valide. Consistante. La base est dans un tat cohrent la fin de la transaction qu'elle soit valide ou annule. Isol. La transaction n'est pas visible par les autres transactions tant qu'elle n'est pas valide (voir la section prcdente). Durable. Une fois la transaction valide, elle doit persister mme en cas d'incident matriel.

6.2.17 DBLink et vues

Sous Oracle, lexcution de requtes ayant des jointures entre des tables adresses par un DBLink, comme illustr dans la requte ci-aprs, pose souvent des problmes de performances. Une solution de contournement consiste crer une vue effectuant la jointure dans la base distante et interroger cette vue travers le DBLink.
Listing6.23: Requte avec une jointure travers un DBLink
select count(*) from cmd@RemoteBase1 c,cmd_lignes@RemoteBase1 cl where c.nocmd = cl.nocmd and noclient=41256

Listing6.24: Requte avec une jointure dans une vue et interrogation de la vue travers un DBLink
-- Cration d'une vue sur la base distante. Create view Vue1 AS select cl.*,c.noclient,c.datecommande,c.etatcommande from cmd c,cmd_lignes cl where c.nocmd = cl.nocmd ; -- Requte locale faisant reference la vue sur la base distante. select count(*) from Vue1@RemoteBase1 where noclient=41256

7
Techniques d'optimisation desrequtes avances
7.1 Utilisation des hints sous Oracle

Les hints (indications en anglais) sont des conseils que lon donne loptimiseur pour lorienter dans le choix dun plan dexcution. Ce dernier sera du coup diffrent de celui quil aurait choisi normalement en estimant que ctait le moins coteux pour excuter la requte demande. Lutilisation des hints peut compenser une erreur destimation de loptimiseur, mais un hint forcera un chemin daccs, mme sil devient compltement aberrant. Il faut bien avoir en tte que loptimiseur, bien quil ne soit pas parfait, sadapte alors quun hint crit dans une requte ne sadaptera pas tant que vous naurez pas rcrit la requte. Loptimiseur nest pas oblig de suivre le conseil (ce qui est plutt rare). Sil ne comprend pas un hint, il lignore sans afficher aucun message derreur (ce qui peut parfois donner le sentiment quil ne suit pas le conseil). Les hints peuvent conduire des gains significatifs et des chutes de performances dsastreuses. Ils ne sont gnralement pas ncessaires, ils doivent tre mis en uvre avec prcaution et parcimonie, vous ne devez les utiliser quen dernier recours et en parfaite connaissance de cause. Avec les versions plus anciennes dOracle, les choses taient diffrentes, loptimiseur tait moins performant et lutilisation des hints tait un passage incontournable. Aujourdhui, ils peuvent certes encore permettre des optimisations, mais cela se restreint gnralement au cas, plutt rare, o loptimiseur fait une mauvaise valuation. Le reste du temps, les hints sont plutt un risque.

178

tude et optimisation desrequtes

Axe 2

Nous allons tudier rapidement les plus utiles, mais il ne faut surtout pas en mettre partout.
MS SQL Server
Tout comme sous Oracle, on retrouve le concept de hint sous SQL Server. Ils font, par contre, pleinement partie de la syntaxe du SQL et peuvent provoquer des erreurs s'ils sont syntaxiquement incorrects. Microsoft met en garde de la mme faon qu'Oracle sur leur mise en uvre qui n'est gnralement pas ncessaire et qui doit tre rserve des administrateurs et des dveloppeurs expriments. Trois types de hints sont disponibles: Les hints de jointures. Placs dans les clauses de jointures, ils permettent de spcifier le type de jointure (LOOP, HASH, MERGE, REMOTE). table1 inner hash join table2 table1 left outer merge join table2 Les hints de requtes. Ils sont placs la fin de la requte dans la clause OPTION. De nombreuses options sont disponibles. Select ... from ... OPTION (MAXDOP 4) Select ... from ... OPTION (FORCE ORDER) Les hints de tables. Placs aprs le nom de la table dans la clause WITH, ils permettent, entre autres, d'agir sur le niveau d'isolation, les verrous ou les index utiliss. Select ... from table1 WITH (SERIALIZABLE , INDEX(myindex) ) Consultez la documentation pour plus d'informations sur les hints. Soyez toujours trs prudent lorsque vous mettez en uvre un hint.

MySQL
On retrouve aussi sous MySQL le concept de hint mais le choix est plus modeste. Ils sont intgrs la syntaxe et se dcomposent en trois types: Le hint de jointure. Plac dans les clauses de jointures, il permet de spcifier l'ordre de jointure de type INNER l'aide du mot cl STRAIGHT_JOIN. table1 STRAIGHT_JOIN table2 on ... Les hints de requtes. Ils sont placs juste aprs le mot cl SELECT. Les valeurs possibles sont : HIGH_PRIORITY, STRAIGHT_JOIN, SQL_SMALL_RESULT, SQL_BIG_RESULT, SQL_BUFFER_RESULT, SQL_CACHE, SQL_NO_CACHE, SQL_CALC_FOUND_ROWS Select SQL_NO_CACHE * from table1

Chapitre 7

Techniques d'optimisation desrequtes avances 179

Les hints de tables. Placs aprs le nom de la table, ils influent sur les index utiliss ou pas. La syntaxe est la suivante: {USE | IGNORE | FORCE } {INDEX|KEY} [{FOR {JOIN|ORDER BY|GROUP BY}] ([index_list]) Select ... from table1 USE INDEX(myindex) Consultez la documentation pour plus d'informations sur les hints. Soyez toujours trs prudent lorsque vous mettez en uvre un hint.

7.1.1

Syntaxe gnrale

Les hints sont placs dans un commentaire qui suit le mot cl de linstruction (SELECT, INSERT, UPDATE, DELETE, MERGE). Le commentaire est de la forme /*+
monhint */

ou --+

monhint:

Select /*+ monhint */ nom from clients . . .

Attention, sil y a un espace avant le +, le hint ne sera pas considr comme tel. Si le hint est incorrect (syntaxiquement ou smantiquement), il est simplement ignor. Les hints peuvent avoir frquemment des paramtres qui sont des noms de table et dindex. Dans le cas des tables, il faut en fait mentionner lalias associ la table et non pas la table elle-mme, puisquelle peut apparatre plusieurs fois dans la requte. Rappel: quand aucun alias nest spcifi pour une table, lalias par dfaut est le nom de la table. Sil y a plusieurs paramtres dans le hint, ils sont spars par un espace (pas de virgule).
Select /*+ monhint(t) */ nom from client t . . .

Il est possible de spcifier plusieurs hints en les crivant les uns derrire les autres spars par un espace.
select /*+index(cmd is_cmd_client) no_index(cli pk_clients) count(datecommande) from clients cli join cmd on cli.noclient=cmd.noclient */

7.1.2

Les hints Optimizer Goal

All_Rows. Spcifie que cette requte privilgiera la rcupration de toutes les lignes (voir Chapitre1, section1.4.2, "Loptimiseur CBO (Cost Based Optimizer)").

180

tude et optimisation desrequtes

Axe 2

First_Rows(n). Spcifie que cette requte privilgiera la rcupration des n premires lignes. Ce hint encouragera lutilisation des index mme pour des gros ensembles scanner. Dans la requte ci-aprs, lindex sur le champ Livre est utilis si on spcifie le hint, sinon il ne lest pas:
select /*+ First_Rows(10)*/ * from cmd_lignes t where nolivre<102354

7.1.3

Les hints Access Path

Full (table_alias).

Permet de forcer un parcours complet dune table au lieu

dutiliser un index.
index (table_alias Nom_index). Permet de forcer lutilisation dun index en partic-

ulier lors de laccs une table. Ce hint est le plus utilis car il empche loptimiseur dcarter, tort, un index sil y a des erreurs destimation des cardinalits.
select /*+index(cmd is_cmd_client) */ * from cmd where noclient >10000

No_index (table_alias Nom_index).

Interdit lutilisation dun index particulier

lors de laccs une table.


select /*+no_index(cmd is_cmd_client) */ * from cmd where noclient >10000000

index_FFS (table_alias Nom_index).

Permet de forcer un Fast Full Scan sur un Interdit un Fast Full Scan sur un index.

index.
No_index_FFS (table_alias Nom_index). index_SS (table_alias Nom_index).

Permet de forcer un Skip Scan sur un index. Interdit un Skip Scan sur un index.

No_index_SS (table_alias Nom_index).

index_RS (table_alias Nom_index). Permet de forcer un Range Scan sur un index

(napparat pas dans la documentation officielle).


iNDeX_COmbiNe(table_alias Nom_index1 Nom_index2 ). Force une combinaison de type bitmap de plusieurs index B*Tree (voir Figure5.8, la section5.2.4, "Index bitmap").
select /*+ INDEX_COMBINE(clients is_clients_pays is_clients_nom ) from clients where pays ='France' and nom = 'Roberts' */ *

iNDeX_JOiN (table_alias Nom_index1 Nom_index2 ). Force une combinaison par

jointure de plusieurs index.

Chapitre 7

Techniques d'optimisation desrequtes avances 181

7.1.4

Les hints Query Transformation

NO_QUeRY_TRANSFORmATiON. USe_CONCAT. Transforme

Interdit toutes les transformations de requtes.

des prdicats OR en concatnation (une sorte dUNION).

select /*+ USE_CONCAT */ * from cmd_lignes where nocmd=14827 or nolivre=3289

La requte prcdente ressemble celle-ci ( la gestion de doublons prs):


select * from cmd_lignes where nocmd=14827 union select * from cmd_lignes where nolivre=3289

NO_eXpAND. ReWRiTe.

Interdit la transformation des prdicats OR en concatnation. Cest loppos du hint USE_CONCAT. Force lutilisation des vues matrialises sil y en a de disponibles. Interdit lutilisation des vues matrialises. Force lintgration dune vue dans le schma dexcution

NO_ReWRiTe.

meRge (query_block).

principal.
select /*+MERGE(C)*/ cli.noclient,nom, C.Nbr from clients cli, (select noclient,count(*) Nbr from cmd group by noclient) C where cli.noclient=C.noclient;

Limpact sur le plan dexcution de la requte prcdente est de supprimer la cration intermdiaire de la vue.
----------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| ----------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 45000 | 1713K| | 2390 (3)| |* 1 | HASH JOIN | | 45000 | 1713K| 1104K| 2390 (3)| | 2 | TABLE ACCESS FULL | CLIENTS | 45000 | 571K| | 171 (1)| | 3 | VIEW | | 45156 | 1146K| | 2083 (3)| | 4 | HASH GROUP BY | | 45156 | 220K| 12M| 2083 (3)| | 5 | TABLE ACCESS FULL| CMD | 1000K| 4882K| | 890 (2)| -----------------------------------------------------------------------------

Dans le plan dexcution ci-aprs (avec le hint MERGE), on constate que la jointure est faite entre cmd et clients et ensuite seulement le GROUP BY est effectu.

182

tude et optimisation desrequtes

Axe 2

------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| ------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 996K| 40M| | 12663 (1)| | 1 | HASH GROUP BY | | 996K| 40M| 99M| 12663 (1)| |* 2 | HASH JOIN | | 996K| 40M| 2200K| 1703 (1)| | 3 | TABLE ACCESS FULL | CLIENTS | 45000 | 1669K| | 171 (1)| | 4 | INDEX FAST FULL SCAN| IS_CMD_CLIENT | 1000K| 4882K| | 611 (1)| -------------------------------------------------------------------------------------

Empche lintgration dune vue dans le schma dexcution principal. Cest loppos du hint MERGE.
UNNeST.

NO_meRge (query_block).

Permet de faire des transformations de type boucle imbrique vers jointure.

NO_UNNeST. Empche les transformations de type boucle imbrique vers jointure qui sont, trs souvent, effectues lorsquil y a des sous-requtes. pUSH_pReD(query_block) / NO_pUSH_pReD(query_block).

Force ou interdit

lapplication dun prdicat dans une vue.


7.1.5 Les hints de jointure

LeADiNg.

Permet de spcifier la table menante dans une jointure.

select /*+leading (cmd cli) */ cli.noclient,nom, cmd.datecommande from clients cli,cmd where cli.noclient=cmd.noclient and cli.noclient between 100000 and 100020

ORDeReD. Permet de spcifier que les jointures doivent tre faites dans lordre dappa-

rition dans la clause


USe_NL,NO_USe_NL.

FROM.

Force ou interdit une jointure par boucles imbriques (Nested

Loop).
USe_NL_WiTH_iNDeX.

Force une jointure par boucles imbriques seulement si un index est prsent sur la table jointe. Ce hint sera sans effet si lindex disparat ou est invalid. En effet, limpossibilit dutiliser un index pourrait avoir des consquences dsastreuses en termes de performances: une boucle imbrique sur une grosse table non indexe a des performances catastrophiques car elle provoque un parcours complet de la table pour chaque valeur de la table menante.

Chapitre 7

Techniques d'optimisation desrequtes avances 183

USe_meRge, NO_USe_meRge. USe_HASH, NO_USe_HASH.

Force ou interdit une jointure par Sorted Merge.

Force ou interdit une jointure par table de hachage.

7.1.6

Autres hints

Il existe une srie de hints destins au paralllisme que nous tudierons la section7.2.1 de ce chapitre.
CACHe (table_alias). Dsigne la table comme trs utilise pour quelle reste longtemps dans le cache. Cest le comportement par dfaut pour les petites tables.

Dsigne la table comme peu utilise pour quelle quitte rapidement le cache. Cest le comportement par dfaut pour les grosses tables.
Qb_NAme.

NOCACHe (table_alias).

Permet de spcifier un bloc pour y appliquer un hint.

SELECT /*+ QB_NAME(qb) FULL(@qb c) */ * FROM clients c WHERE nom = 'SMITH';

DRiViNg_SiTe.

Permet dinfluer sur lexcution de requtes utilisant des DBLink et des bases distantes.

DYNAmiC_SAmpLiNg (table_alias niveau_echantillonnage).

Permet de faire un chantillonnage dynamique des donnes pour complter les informations fournies par les statistiques, afin de les ajuster avec les prdicats de la requte (voir Chapitre5, section5.1.3, "Slectivit, cardinalit, densit").

7.2

Excution parallle

Il sagit ici de faire excuter une requte par plusieurs processeurs de faon parallle. Nous nallons pas entrer dans le dtail de tout ce quil est possible de faire avec lexcution parallle, mais juste donner un aperu. Comme vous pouvez vous en douter, ce dcoupage en sous-tches a un certain cot dorganisation. De plus, lexcution parallle a pour caractristique de sexcuter principalement en faisant des lectures disques plutt quen utilisant le cache de donnes. Cela conforte lide que cette opration est plutt destine travailler

184

tude et optimisation desrequtes

Axe 2

sur de gros volumes. Ce type doptimisation ne sera pertinent que dans les cas suivants:

Il y a plusieurs processeurs disponibles. Il ny a pas de goulet dtranglement au niveau du disque dur. Il y a suffisamment de choses faire pour que la mise en place du paralllisme soit compense par le gain li ce dernier.

Lutilisation du paralllisme sur des cas non adapts provoquera un ralentissement des oprations. Lexcution parallle est particulirement adapte des tables partitionnes, rparties sur des disques diffrents. Les oprations concernes par la paralllisation sont:

les requtes interrogations de type SELECT; les requtes de manipulation des donnes (LMD: UPDATE, DELETE sur partitions diffrentes et INSERT sur requte); certaines oprations de LDD.

Lexcution parallle peut tre configure au niveau de la session pour les trois types doprations laide des paramtres suivants:
PARRALEL QUERY PARRALEL DML PARRALEL DDL

Les paramtres de paralllismes peuvent avoir une des trois valeurssuivantes:


ENABLE.

Les fonctions de paralllisme seront utilises si elles sont spcifies par un hint dune requte ou au niveau dun objet manipul. Les fonctions de paralllisme ne seront pas utilises.

DISABLE. FORCE.

Permet de forcer un niveau de paralllisme.

Par dfaut, le paralllisme est configur ainsi:


PARRALEL QUERY = ENABLE

Chapitre 7

Techniques d'optimisation desrequtes avances 185

PARRALEL DML = ENABLE PARRALEL DDL = DISABLE

Si vous souhaitez spcifier des hints de paralllisme dans les requtes DML, vous devrez dabord excuter linstruction suivante:
alter session enable parallel dml;

Lexcution parallle peut tre configure au niveau de chaque requte comme montr ci-aprs:
select /*+ PARALLEL(c , 4) */max(C.DATECOMMANDE) from cmd c; insert /*+ parallel (Cmd2009,4,1) */ into Cmd2009 select * from cmd Where datecommande<To_Date('2010','YYYY'); alter index IS_CMD_CLIENT rebuild parallel 4;

Lexcution parallle peut tre configure au niveau des objets. Ainsi, toute opration sur ces objets sera paralllise sans que vous ayez le spcifier au niveau de lopration.
ALTER TABLE cmd PARALLEL (DEGREE 4);

Les oprations parallles prennent gnralement un paramtre, nomm "degr de paralllisme" (DOP, degree of parallelism), qui dfinit le nombre de sous-tches concurrentes qui composeront lopration. Il est important de choisir un DOP en adquation avec le matriel. Cest inutile, voire inefficace, de spcifier un DOP suprieur au nombre dunits de traitement (nombre de CPU nombre de curs par CPU).
7.2.1 Les hints de paralllisme

pARALLeL(table_alias , degr //). Permet de spcifier un niveau de paralllisme

pour les accs une table.


NO_pARALLeL (table_alias).

Permet de dsactiver le paralllisme pour les accs Permet de spcifier un niveau de

une table.
pARALLeL_index (table_alias , idx,degr).

paralllisme sur les Index Scan.


NO_pARALLeL_index (table_alias).

Permet de dsactiver le paralllisme sur les

Index Scan. Permet dinfluer sur les modes de communication entre les soustches pour effectuer les jointures parallles.
pQ_DiSTRibUTe.

186

tude et optimisation desrequtes

Axe 2

MS SQL Server
SQL Server gre aussi le paralllisme de faon assez analogue Oracle. Cependant, il est bien plus efficace sur la paralllisation des petites requtes et active d'ailleurs par dfaut ce comportement (sauf sur les ditions express). Le hint MAXDOP permet d'influer sur le niveau de paralllisme. La valeur1 permet de le dsactiver. Exemple de plan d'excution d'une requte avec un degr de paralllisme 4:
select sum(quantite) from cmd_lignes option (maxdop 4)

Figure7.1 Plan d'excution d'une requte paralllise sous MS SQL Server.

MySQL
MySQL ne propose pas de solution pour exploiter plusieurs processeurs dans une mme requte.

7.3

Utilisation du SQL avanc

Certaines fonctions avances permettent de faire des requtes quil tait quasiment impossible de faire en SQL conventionnel ou alors au prix dune grosse chute des performances. La plupart ont t introduites en version8i ou 9i dOracle, dans les dernires versions de SQL Server et ne sont pas disponibles sous MySQL.
7.3.1 Les Grouping Sets

Ils sont disponibles depuis Oracle 9i et SQL Server 2008. Les Grouping Sets permettent dutiliser les fonctions dagrgats sur plusieurs groupes diffrents dans la mme requte. La requte suivante:
Select JOB,ENAME, count(*) From BIGEMP Group by Grouping Sets ((JOB), (ENAME))

Chapitre 7

Techniques d'optimisation desrequtes avances 187

quivaut smantiquement :
Select JOB,NULL ENAME, count(*) From BIGEMP Group by JOB union all Select NULL,ENAME, count(*) From BIGEMP Group by ENAME

et produit le rsultat ci-aprs:


JOB ENAME COUNT(*) --------- ---------- ---------ALLEN 100001 JONES 100001 FORD 100001 CLARK 100001 MILLER 100001 SMITH 100001 WARD 100001 MARTIN 100001 SCOTT 100001 TURNER 100001 ADAMS 100001 BLAKE 100001 KING 100001 JAMES 100001 SALESMAN 400004 CLERK 400004 PRESIDENT 100001 MANAGER 300003 ANALYST 200002 19 rows selected

En termes de performances, GROUPING SETS devrait normalement tre deux fois plus rapide que deux requtes GROUP BY successives puisquon ne parcourt quune fois lensemble de donnes. Dans les faits, lestimation faite par loptimiseur indique que le cot est deux fois moindre pour la requte utilisant GROUPING SETS que pour la requte utilisant les GROUP BY simples. Cependant, lcart nest plus que de 15% pour les Consistent Gets, et la tendance sinverse en temps dexcution: la requte utilisant des GROUP BY simples est plus rapide sur Oracle. Sur SQL Server, la requte utilisant GROUPING SETS est plus rapide de 20%. Il conviendra, encore plus que dhabitude, dvaluer cette solution dans votre contexte afin de juger de son rel intrt.

188

tude et optimisation desrequtes

Axe 2

7.3.2

Rollup Group By

Il est disponible sur SQL Server, MySQL 5.x et depuis Oracle 9i. Loprateur ROLLUP GROUP BY permet de gnrer les sous-totaux de GROUP BY multicolonnes dans une requte unique, comme si on effectuait successivement les GROUP BY mentionns en supprimant chaque itration le niveau de groupe le plus droite. La requte suivante:
Select Deptno,Job, count(*) From EMP group by rollup(Deptno, Job)

quivaut smantiquement :
Select Deptno, Job, count(*) From EMP Group by Deptno, Job union all Select Deptno,null, count(*) From EMP Group by Deptno union all Select null,null, count(*) From EMP Order by 1,2

et produit le rsultat ci-aprs:


DEPTNO -----10 10 10 10 20 20 20 20 30 30 30 30 JOB COUNT(*) --------- ---------CLERK 1 MANAGER 1 PRESIDENT 1 3 CLERK 2 ANALYST 2 MANAGER 1 5 CLERK 1 MANAGER 1 SALESMAN 4 6 14 13 rows selected

En termes de performances, GROUP BY ROLLUP devrait tre trois fois plus rapide que trois requtes GROUP BY successives, puisque le SGBDR ne parcourt quune fois lensemble de donnes sources. Dans la pratique, le ratio est plutt de 2,2, ce qui est dj bien. Ce ratio se retrouve sur le temps dexcution, le cot de loptimiseur et les Consistent Gets.

Chapitre 7

Techniques d'optimisation desrequtes avances 189

MS SQL Server
Le gain de performances est analogue celui d'Oracle. Les versions antrieures la version2008 utilisent une notation alternative transformant ainsi la requte:
Select Deptno,JOB, count(*) From EMP group by Deptno,job with rollup

MySQL
MySQL supporte la notation ROLLUP. Cependant, les rsultats en performances ne sont pas au rendez-vous, puisque la version ROLLUP est 20% plus lente que celle utilisant trois GROUP BY. La notation est la mme que l'ancienne notation de SQL Server, il faut donc crire ainsi:
Select Deptno,JOB, count(*) From EMP group by Deptno,job with rollup

7.3.3

Cube Group By

Il est disponible sur SQL Server et depuis Oracle 9i. Loprateur CUBE GROUP BY permet de gnrer les sous-totaux de toutes les dimensions des GROUP BY multicolonnes dans une requte unique, comme si on effectuait successivement les GROUP BY en faisant toutes les combinaisons possibles.
Select Deptno,JOB, count(*) From EMP group by cube(deptno,job)

quivaut smantiquement :
Select Deptno,JOB, count(*) From EMP Group by Deptno,JOB union all Select Deptno,null, count(*) From EMP Group by Deptno union all Select null,job, count(*) From EMP Group by job union all Select null,null, count(*) From EMP

190

tude et optimisation desrequtes

Axe 2

et produit le rsultat ci-aprs:


DEPTNO JOB COUNT(*) ------ --------- ---------14 CLERK 4 ANALYST 2 MANAGER 3 SALESMAN 4 PRESIDENT 1 10 3 10 CLERK 1 10 MANAGER 1 10 PRESIDENT 1 20 5 20 CLERK 2 20 ANALYST 2 20 MANAGER 1 30 6 30 CLERK 1 30 MANAGER 1 30 SALESMAN 4 18 rows selected

En termes de performances, GROUP BY CUBE devrait tre quatre fois plus rapide que quatre requtes GROUP BY successives, puisquil ne parcourt quune seule fois lensemble de donnes sources. Dans la pratique, le ratio est plutt de3. Ce ratio se retrouve sur le temps dexcution, le cot de loptimiseur et les Consistent Gets.
MS SQL Server
Le gain de performance est plutt de l'ordre de 50%. Les versions antrieures la version2008 utilisent une notation alternative transformant ainsi la requte:
Select Deptno,JOB, count(*) From EMP group by Deptno,job with cube

MySQL
Ne supporte pas la notation CUBE.

Chapitre 7

Techniques d'optimisation desrequtes avances 191

7.3.4

Utilisation de WITH

Loprateur WITH, introduit avec Oracle 9i, permet de dclarer une sous-requte qui va tre utilise plusieurs fois dans la requte, ce qui vite la rptition dune sousrequte plusieurs endroits de la requte. Cela prsente un intrt en termes de clart de code mais offre aussi lavantage damliorer parfois les performances en favorisant la cration de tables temporaires internes. tudions la requte suivante qui affiche les informations relatives la plus grosse ligne de commande de livres de lditeur Pearson:
select cmd.nocmd,cmd.noclient,cmd.datecommande, cl.quantite,cl.montant,cl.nolivre from cmd join cmd_lignes cl on cmd.nocmd=cl.nocmd join livres l on cl.nolivre=l.nolivre where editeur='Pearson' and quantite=(select max(cl.quantite) quantite from cmd_lignes cl join livres l on cl.nolivre=l.nolivre where editeur='Pearson' )

Nous remarquons que la requte principale et la sous-requte expriment toutes les deux une jointure entre les tables livres et cmd_lignes et filtrent sur lditeur Pearson. Le plan dexcution nous apprend que le SGBDR fait aussi le travail deux fois. La requte ci-aprs est smantiquement identique mais ne rpte pas les oprations, ni dans la requte, ni dans le plan dexcution:
with PearsonBookLignes as (select cmd.nocmd,cmd.noclient,cmd.datecommande ,cl.quantite,cl.montant,cl.nolivre from cmd join cmd_lignes cl on cmd.nocmd=cl.nocmd where nolivre in (select nolivre from livres where editeur='Pearson') ) select L.* from PearsonBookLignes L where quantite=( select max(quantite) from PearsonBookLignes )

La version utilisant WITH est presque deux fois plus performante. Cependant, il faut prendre garde car si la requte nomme dans la clause WITH est trop volumineuse, la tendance peut sinverser. Dans ce cas, lutilisation du hint /*+ inline */ dans la requte situe dans le WITH pourra tre adapte.
MS SQL Server
Cette notation est disponible depuis SQL Server 2005, mais nous n'avons pas not de gains de performance significatifs.

192

tude et optimisation desrequtes

Axe 2

7.3.5

Les fonctions de classement (ranking)

Le SQL ntant pas un langage procdural, il nest pas facile dexprimer des choses telles que le 10esalaire, le 50eemploy ou le numro dordre dun classement. Dans le pass, sous Oracle, on utilisait la pseudo-colonne Rownum et sous SQL Server et MySQL, la clause LIMIT, mais cela sapparentait du bricolage. Les versions8.1.7 dOracle et 2005 de SQL Server ont introduit les fonctions de classement (ranking). Elles permettent dobtenir le classement dun enregistrement dans un ensemble quand on a spcifi les critres de classement. Par exemple, la requte ci-aprs donne pour chaque employ le rang de son salaire, son quartile, son pourcentage dans la distribution et le numro de la ligne:
Select ename,sal,RANK() over(order by sal desc) Rang ,DENSE_RANK() over(order by sal desc) RangDense ,ROW_NUMBER() over(order by sal desc ) NoLigne ,round(PERCENT_RANK() over(order by sal desc)*100) PctRang ,NTILE(4) over(order by sal desc ) Quartile From EMP ENAME SAL RANG RANGDENSE NOLIGNE PCTRANG QUARTILE ------ ------ ----- ---------- -------- ------- -------KING 5000 1 1 1 0 1 FORD 3000 2 2 2 8 1 SCOTT 3000 2 2 3 8 1 JONES 2975 4 3 4 23 1 . . . . . . JAMES 950 13 11 13 92 4 SMITH 800 14 12 14 100 4

La diffrence entre la fonction RANK et la fonction DENSE_RANK se situe au niveau de la gestion des enregistrements ayant le mme classement. Dans notre exemple, SCOTT et FORD ont le mme salaire et sont tous les deux deuximes. La fonction RANK considre quil ny a pas de troisime et JONES est donc quatrime, alors que la fonction DENSE_RANK considre que JONES est troisime. Le classement est tabli en suivant la clause ORDER BY mentionne dans la clause OVER( ) associe la fonction. PERCENT_RANK donne la position en pourcentage. NTILE(N) donne le N-tile de la valeur, donc pour N=4 donne le quartile. ROW_NUMBER donne le numro de la ligne suivant lordre spcifi sans doublon. Ces fonctions permettent aussi deffectuer des classements par partition, cest--dire sur des sous-ensembles de donnes. Par exemple, la requte ci-aprs donne pour

Chapitre 7

Techniques d'optimisation desrequtes avances 193

chaque employ le rang de son salaire au sein de son dpartement. On constate qu chaque changement de dpartement le classement recommence 1.
Select deptno,ename,sal, RANK() over (PARTITION BY deptno order by sal desc) Rang From EMP DEPTNO ENAME SAL RANG ---------- ---------- ---------- ---------10 KING 5000 1 10 CLARK 2450 2 10 MILLER 1300 3 20 SCOTT 3000 1 20 FORD 3000 1 20 JONES 2975 3 20 ADAMS 1100 4 20 SMITH 800 5 30 BLAKE 2850 1 . . . . . .

Les fonctions de classement permettent dcrire des requtes qui ramnent les npremiers enregistrements suivant un ordre (Topn). Pour cela, il suffit de mettre une condition sur le classement. Cependant, il nest syntaxiquement pas possible de spcifier ces fonctions dans la clause WHERE. La requte suivante provoque lerreur: ORA-30483: fonctions de fentrage interdites ici.
Select deptno,ename,sal,RANK() over (PARTITION BY deptno order by sal desc) Rang From EMP where RANK() over (PARTITION BY deptno order by sal desc) =1;

Nous devons utiliser une sous-requte:


Select deptno,ename,sal From (Select deptno,ename,sal ,RANK() over (PARTITION BY deptno order by sal desc) Rang From EMP ) where Rang=1;

Pour obtenir le rsultat suivant:


DEPTNO -----10 20 20 30 ENAME SAL ---------- --------KING 5000,00 SCOTT 3000,00 FORD 3000,00 BLAKE 2850,00

Lutilisation des fonctions de ranking pour les requtes de type Topn namliore pas forcment les performances par rapport une solution simple avec une sous-requte

194

tude et optimisation desrequtes

Axe 2

comme dans lexemple ci-aprs (il nest cependant pas toujours possible de transformer la requte de faon aussi simple):
Select deptno,ename,sal From EMP where (deptno,sal) in ( Select deptno,max(sal) From EMP group by deptno )

7.3.6

Autres fonctions analytiques

Les fonctions analytiques ont la capacit de travailler sur un ensemble denregistrements de faon simple et souvent performante (les fonctions de classement en font partie). Les fonctions dagrgations classiques (MIN, MAX, SUM, AVG, COUNT) existent en versions analytiques. Dans ce mode, elles sappliquent sur une fentre glissante autour de lenregistrement. LEAD et LAG permettent de manipuler les enregistrements prcdents et suivants. Lexemple ci-aprs permet de faire des moyennes glissantes grce AVG sur une fentre couvrant les quatre enregistrements prcdents et calcule lcart de la colonne Sal avec les lignes suivantes et prcdentes grce aux fonctions LEAD et LAG:
SELECT ename, sal ,AVG(sal) OVER (ORDER BY sal ROWS BETWEEN 5 PRECEDING AND 1 PRECEDING) AS MoyenneGlissante ,sal-lag(sal,1) OVER (ORDER BY sal ) AS EcartPrec ,lead(sal,1) OVER (ORDER BY sal )-sal AS EcartSuivant FROM emp order by sal; ENAME SAL MOYENNEGLISSANTE ECARTPREC ECARTSUIVANT ------- ------ ---------------- ---------- -----------SMITH 800 150 JAMES 950 800 150 150 ADAMS 1100 875 150 150 WARD 1250 950 150 0 . . . . . . SCOTT 3000 2275 25 0 FORD 3000 2575 0 2000 KING 5000 2855 2000

Lexemple ci-aprs montre comment faire une recherche du percentile mdian de chaque dpartement. La fonction PERCENTILE_CONT recherche le percentile de faon continue par interpolation, alors que la fonction PERCENTILE_DISC retourne la valeur prsente dans les donnes immdiatement infrieures ou gales la version continue.

Chapitre 7

Techniques d'optimisation desrequtes avances 195

SELECT deptno ,avg(sal) as Moyenne ,PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY sal) as mediane ,PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY sal) as mediane_disc FROM emp group by deptno; DEPTNO MOYENNE MEDIANE MEDIANE_DISC ------ ------- ---------- -----------10 2916 2450 2450 20 2175 2975 2975 30 1566 1375 1250

Les fonctions REGR_xxx permettent deffectuer des rgressions linaires sur les donnes. (Voir la documentation de rfrence SQL dOracle.) Concernant lutilisation de fonctions dagrgations personnalises, un besoin rcurrent est de pouvoir lister, dans une colonne, les enregistrements lis par une relation matre/dtails. Cette opration tait possible dans le pass grce une fonction qui parcourait le sous-ensemble laide dun curseur. la version9, une autre manire plus lgante tait apparue, partir dun type et dune mthode dagrgation, mais ctait compliqu mettre en uvre et toujours moins performant quune solution native. La version dOracle11g Release2 rsout ce besoin en ajoutant la fonction dagrgation native LISTAGG, qui permet de concatner des chanes de caractres avec un sparateur dans un champ, comme illustr dans cet exemple:
select deptno,LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) from emp group by deptno; DEPTNO -----10 20 30 LISTE -------------------------------------CLARK,KING,MILLER ADAMS,FORD,JONES,SCOTT,SMITH ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD as Liste

7.3.7

L'instruction MERGE

Linstruction MERGE, introduite avec Oracle 9i, permet de fusionner une table source dans une table destination. Tous les enregistrements de lensemble de donnes sources prsents dans la table de destination seront mis jour et ceux qui ne sont prsents que dans la source seront insrs. Ceux qui ne sont prsents que dans la destination ne seront pas modifis. Cette instruction revient faire un Update et un Insert. Elle apporte un gain de performances pour les oprations de fusion de table. La syntaxe est la suivante:

196

tude et optimisation desrequtes

Axe 2

MERGE INTO <TableDestination> USING <TableSource> on (<ClauseJointure>) WHEN MATCHED THEN UPDATE SET <Champ>=<Expression>, . WHEN NOT MATCHED THEN INSERT (Champ, ) values (Expression, )

MS SQL Server
L'instruction MERGE est aussi disponible. Elle peut intgrer galement le fait de supprimer les enregistrements prsents dans la destination et pas dans la source l'aide de la clause
WHEN NOT MATCHED BY SOURCE.

MySQL
MySQL ne propose pas de solution quivalente MERGE.

7.3.8

Optimisation des updates multitables

Pour faire un update dans une table relativement des donnes contenues dans une autre table, on crit habituellement des sous-requtes. Par exemple, la requte suivante augmente les salaires des employs lists dans la table augmentation:
update bigemp e set sal=sal+(select Montant from augmentation where empno=e.empno) where empno in (select empno from augmentation )

Une premire solution possible pour amliorer les performances consiste utiliser linstruction MERGE ampute de la clause WHEN NOT MATCHED. Cette solution peut apporter un gain de performance allant jusqu 10%.
MERGE into bigemp E using augmentation A on (a.empno=e.empno) WHEN MATCHED THEN UPDATE set sal=sal+Montant

Une autre solution, particulirement mconnue, est lutilisation dune vue dynamique dans linstruction UPDATE:
update (select sal,Montant from augmentation a, bigemp e where a.empno=e.empno) set sal=sal+Montant

Cette solution apporte un gain trs significatif, puisque le temps dexcution de la requte UPDATE passe de 33secondes 19secondes. Lexplication se trouve facilement dans les plans dexcution ci-aprs. En effet, la dernire solution neffectue quun accs la table augmentation. Les Consistent Gets passent de 2949005 12781.

Chapitre 7

Techniques d'optimisation desrequtes avances 197

Figure7.2 Plan d'excution de l'UPDATE avec sousrequte.

Figure7.3 Plan d'excution de l'UPDATE avec jointure.

MS SQL Server
La motivation nous poussant remplacer une instruction UPDATE par un MERGE n'existe pas sous SQL Server, car l'instruction UPDATE est capable de faire un UPDATE en utilisant une jointure.

MySQL
MySQL ne propose pas de solution alternative pour amliorer les updates multitables.

198

tude et optimisation desrequtes

Axe 2

7.3.9

Insertion en mode Direct Path

Le mode dinsertion Direct Path effectue les insertions dans de nouveaux blocs de donnes, sans passer par le buffer cache. Le gain potentiel rside dans lconomie de la recherche de place dans les blocs existants et lconomie de mmoire dans le cache. Les inconvnients de ce mode sont nombreux aussi:

Il crit directement sur les disques. Si ces derniers sont peu performants ou occups, la tendance peut sinverser. Il pose un verrou sur toute la table. Ce verrou peut tre long obtenir et pnalisant pour les autres transactions. Un COMMIT est obligatoire immdiatement aprs une insertion.

Pour activer les insertions en mode Direct Path, il suffit dajouter le hint APPEND linstruction INSERT. Ce hint est utilisable sur les requtes INSERT utilisant une requte SELECT.
INSERT /*+ APPEND */ INTO ma_table SELECT * from autre_table

En PL/SQL, avec linstruction FORALL que nous tudierons la section7.4.3 de ce chapitre, le mode Direct Path est activable laide du hint APPEND_VALUES.

7.4
7.4.1

PL/SQL
Impact des triggers

Les triggers sont des outils trs pratiques mais qui peuvent nuire trs srieusement aux performances sur des insertions massives de donnes. Il faudra particulirement veiller lefficacit du code contenu dans les triggers des tables trs mouvementes. Mme si le code du trigger est optimal, lappel mme du trigger un cot. Nous illustrons ce phnomne en transfrant le contenu de la table client (45000enregistrements) dans la table clients2 en convertissant le champ Nom en majuscules, soit en appelant la fonction UPPER() dans une requte SQL, soit avec un trigger qui effectue cette opration.
Listing7.1: Premire solution, compltement en SQL
insert into clients2 select noclient, upper(nom), prenom, adresse1, adresse2, codepostal, ville, pays, tel, email from clients

Chapitre 7

Techniques d'optimisation desrequtes avances 199

Listing7.2: Deuxime solution, utilisant un trigger PL/SQL


create or replace trigger TRG_BEFORE_INS_CLIENTS2 before insert on clients2 for each row begin :new.nom:=upper(:new.nom); end; / insert into clients2 select noclient, nom, prenom, adresse1, adresse2, codepostal, ville, pays, tel, email from clients

Le rsultat est sans appel : la premire solution sexcute en 94 ms, alors que la deuxime, avec le trigger, sexcute en 485ms. Lcart de temps correspond principalement linvocation du trigger PL/SQL. Il faut essayer de rduire les excutions des triggers et, pour cela, la clause mconnue WHEN peut tre utile. Elle permet dvaluer une condition afin de dcider dexcuter le trigger ou pas. Dans le cadre de notre exemple, il est inutile dexcuter le trigger si la donne est dj en majuscules, nous pouvons donc mettre cela en condition pralable dans la clause WHEN.
Listing7.3: Troisime solution, utilisant un trigger PL/SQL avec une clause WHEN
CREATE OR REPLACE TRIGGER TRG_BEFORE_INS_CLIENTS2 before insert on clients2 for each row when (new.nom!=upper(new.nom)) begin :new.nom:=upper(:new.nom); end; / insert into clients2 select noclient, upper(nom), prenom, adresse1, adresse2, codepostal, ville, pays, tel, email from clients

Nous constatons que si les donnes en entre sont dj en majuscules, le gain est trs significatif, puisque le temps dexcution passe 109ms, soit un surcot de 15ms. Ce gain provient du fait quil ny a pas invoquer le moteur PL/SQL pour tester la clause WHEN. Si les donnes ne sont pas en majuscules, le surcot est l aussi de 15ms (on passe de 485ms 500ms). Une autre solution pour viter lexcution inutile de trigger se trouve au niveau de la clause OF sur les triggers UPDATE. Cette clause permet de nexcuter le trigger que si les colonnes quelle spcifie sont prsentes dans la requte UPDATE. Lutilisation de cette clause avec un trigger en UPDATE qui effectue le mme travail que le trigger INSERT est illustre ci-aprs.

200

tude et optimisation desrequtes

Axe 2

Listing7.4: Trigger utilisant une clause UPDATE OF


CREATE OR REPLACE TRIGGER TRG_BEFORE_UPD_CLIENTS2 before update OF nom on clients2 for each row begin :new.nom:=upper(:new.nom); end; / update clients2 set prenom=prenom;

Lexcution de la requte UPDATE ne concernant pas la colonne Nom prend 469ms avec la clause OF alors quelle prend sinon 1125ms cause de lexcution inutile du trigger et de la rcriture inutile de la valeur du champ Nom quelle ncessite.
7.4.2 Optimisation des curseurs (BULK COLLECT)

La manire classique en PL/SQL consiste utiliser des curseurs dans des boucles FOR qui permettent de rcuprer les lignes une par une. Cela fonctionne bien mais ce nest pas trs performant lorsque le volume des enregistrements devient important car il ny a quun enregistrement rcupr (fetch) par itration. Afin damliorer les performances de la rcupration des enregistrements, nous avons notre disposition les instructions BULK COLLECT utilisables dans les instructions suivantes :
Select .. Into Fetch .. Into Returning .. Into

La rcupration seffectue alors par blocs dans des tableaux et non pas dans des variables scalaires. Il suffit juste de faire prcder le mot cl INTO par BULK COLLECT. Illustrons sa mise en uvre par le remplacement dun curseur sur un programme simple qui calcule la somme des salaires:

Listing7.5: Version en PL/SQL classique


declare Cursor c1 is select sal from bigemp; somme number; begin somme:=0;

Chapitre 7

Techniques d'optimisation desrequtes avances 201

for rec in C1 loop somme:=somme+rec.sal; end loop; dbms_output.put_line(somme); end;

Temps dexcution: 1,26s

Listing7.6: Version en PL/SQL utilisant SELECT BULK COLLECT INTO


declare somme number; TYPE Table_N IS table OF Number ; lstsal Table_N; begin somme:=0; SELECT sal BULK COLLECT INTO lstsal FROM bigemp; for j in lstsal.first..lstsal.last loop somme:=somme+lstsal(j); end loop; dbms_output.put_line(somme); end;

Temps dexcution: 0,51s (On constate un gain de performances significatif.)

On constate que la solution utilisant linstruction BULK COLLECT dissocie la rcupration des donnes de leur traitement en les stockant dans un tableau. Cette solution, en plus du gain de performances, offre si ncessaire plus de flexibilit au niveau du parcours des donnes issues de la requte. Le fait de stocker le rsultat dans un tableau ne contraint pas davoir un parcours unidirectionnel comme limpose un curseur classique. Cependant, comme rien nest jamais magique, cette seconde solution consomme plus de ressource mmoire. Il se peut que cette solution pose des problmes lis une saturation de la mmoire si le volume des donnes est trop important. Si cest le cas, vous pouvez utiliser un curseur BULK COLLECT. Il sagit dun curseur qui rcupre non pas un seul enregistrement par fetch mais un ensemble denregistrements qui sont mis dans un tableau dont la taille est spcifie laide de la clause LIMIT. Cette technique est une solution intermdiaire entre le curseur classique et le SELECT INTO BULK COLLECT, qui permet de rcuprer les donnes par paquets de taille intermdiaire. Cette solution ncessite gnralement lutilisation de deux boucles imbriques (voir Listing7.7).

202

tude et optimisation desrequtes

Axe 2

Listing7.7: Version en PL/SQL utilisant FETCH BULK COLLECT INTO


declare Cursor c1 is select sal from bigemp e; somme number; TYPE Table_N IS table OF Number ; lstsal Table_N; begin somme:=0; OPEN c1; LOOP FETCH c1 BULK COLLECT INTO lstsal LIMIT 1000; EXIT WHEN c1%NOTFOUND; for j in lstsal.first..lstsal.last loop somme:=somme+lstsal(j); end loop; end loop; dbms_output.put_line(somme); end;

Le temps dexcution de cette version est de 0,64seconde. Cest toujours en progrs significatif par rapport un curseur conventionnel mais en recul par rapport la solution SELECT INTO BULK COLLECT. Cela sexplique par le fait que la requte ne pose pas de problme de volume, le cot des oprations supplmentaires impliques par cette solution nest compens par aucun gain. Afin de mettre en vidence dventuels problmes de performances lis aux volumes, nous allons faire quelques tests en faisant fluctuer la clause LIMIT sur une variante qui ramne les enregistrements complets au lieu de ne ramener que la colonne Sal.
Listing7.8: Version en PL/SQL utilisant FETCH BULK COLLECT ramenant les enregistrements entiers
declare Cursor c1 is select e.* from bigemp e; somme number; TYPE Table_N IS table OF c1%rowtype ; lstsal Table_N; begin somme:=0; OPEN c1; LOOP FETCH c1 BULK COLLECT INTO lstsal LIMIT 100; EXIT WHEN c1%NOTFOUND; for j in lstsal.first..lstsal.last loop somme:=somme+lstsal(j).sal; end loop; end loop; dbms_output.put_line(somme); end;

Chapitre 7

Techniques d'optimisation desrequtes avances 203

Tableau7.1: Analyse des performances en fonction de la clause LIMIT

Clause LIMIT 1 10 100 1 000 10 000 100 000 500 000 1 000 000

Temps d'excution 19,5s 4,5s 3,25s 2,59s 2,59s 3,11s 3,27s 3,70s

Nous constatons que la rcupration (fetch) par blocs de quelques milliers denregistrements est optimale pour ce cas-l. La valeur 1000 est une valeur adapte pas mal de cas, elle permet de rduire par 1000 le nombre de fetches tout en utilisant une quantit de mmoire raisonnable pour le tableau. Si vous navez pas le temps de faire une valuation plus approfondie, cest une valeur assez polyvalente qui convient dans la plupart des cas.
7.4.3 Optimisation du LMD (FORALL)

La modification de donnes partir de curseurs (classique ou BULK COLLECT) a pour effet de multiplier le nombre dexcutions dinstructions de type LMD (INSERT, UPDATE, DELETE). Cette mthode peut avoir un impact significativement ngatif sur les performances par rapport du SQL classique. Afin damliorer les performances de ce type dopration, il existe un quivalent au BULK COLLECT pour le LMD au travers de linstruction FORALL qui a la syntaxe suivante:
FORALL index IN lower_bound..upper_bound Instruction_SQL_LMD;

FORALL

permet de manipuler des instructions du LMD avec des tableaux, ce qui rduit le nombre dexcutions de requtes. Chaque FORALL nexcutera linstruction quune seule fois avec des tableaux comme paramtres au lieu de valeurs scalaires.

204

tude et optimisation desrequtes

Axe 2

Listing7.9: Exemple d'utilisation de FORALL


DECLARE TYPE Table_N IS table OF Number ; lstempno Table_N ; lstmontant Table_N ; begin SELECT empno, aug BULK COLLECT INTO lstempno,lstmontant FROM empbigaug; forall j in lstempno.first..lstempno.last UPDATE empbig set SAL=SAL+lstmontant(j) where empno=lstempno(j); end;

Nous allons valuer les performances de cette solution travers un petit programme qui augmente les salaires de la localisation "DALLAS" de 10 et ceux de la localisation "Toulouse" de 31. Le programme est quivalent aux instructions SQL suivantes que nous utilisons comme rfrence:
Listing7.10: Version SQL UPDATE
update bigemp e set sal=sal+(select decode(loc,'CHICAGO',10,'Toulouse',31,0) from bigdept where deptno=e.deptno) where deptno in (select deptno from bigdept where loc in ('CHICAGO','Toulouse') );

Temps dexcution: 11,32 s


Listing7.11: Version SQL MERGE
merge into bigemp e using (select empno,sal+decode(loc,'CHICAGO',10,'Toulouse',31,0) NewSal from bigemp e,bigdept d where e.deptno=d.deptno and loc in ('CHICAGO','Toulouse')) A on (E.empno=A.empno) when matched then update Set sal=Newsal;

Temps dexcution: 12,81s

Listing7.12: Version SQL UPDATE optimis avec jointure


update (SELECT sal ,DECODE (loc, 'CHICAGO', 10, 'Toulouse', 31, 0) bonus FROM bigdept,bigemp WHERE bigdept.deptno = bigemp.deptno and loc IN ('CHICAGO', 'Toulouse') ) set sal=sal+bonus;

Temps dexcution: 9,21s

Chapitre 7

Techniques d'optimisation desrequtes avances 205

Listing7.13: Version PL/SQL de base


declare Cursor c1 is select empno,sal,loc from bigemp e,bigdept d where e.deptno=d.deptno for update of e.sal; begin for rec in C1 loop if rec.loc in ('CHICAGO','Toulouse') then update bigemp set sal=sal+decode(rec.loc,'CHICAGO',10,'Toulouse',31,0) where current of c1; end if; end loop; end;

Temps dexcution: 66,07s

Cette version effectue le filtrage des lignes dans le PL/SQL et ramne des lignes inutilement. Le filtrage des enregistrements dans un bloc PL/SQL au lieu dune clause WHERE est gnralement bannir.
Listing7.14: Version PL/SQL de base avec une clause WHERE dans le curseur
declare Cursor c1 is select empno,sal,loc from bigemp e,bigdept d where e.deptno=d.deptno and loc in ('CHICAGO','Toulouse') for update of e.sal; begin for rec in C1 loop update bigemp set sal=sal+decode(rec.loc,'CHICAGO',10,'Toulouse',31,0) * where current of c1; end loop; end;

Temps dexcution: 28,51s

Nous voyons que, gnralement, les instructions SQL simples sont plus performantes que l'quivalent en PL/SQL.
Listing7.15: Version utilisant un curseur BULK COLLECT
declare Cursor c1 is select empno,sal,loc,e.rowid from bigemp e,bigdept d where e.deptno=d.deptno and loc in ('CHICAGO','Toulouse'); TYPE C1RecTab IS TABLE OF c1%rowtype; Recs C1RecTab;

206

tude et optimisation desrequtes

Axe 2

begin OPEN c1; LOOP FETCH c1 BULK COLLECT INTO Recs LIMIT 1000; EXIT WHEN c1%NOTFOUND; for j in Recs.first..Recs.last loop update bigemp set sal=sal+decode(recs(j).loc,'CHICAGO',10,'Toulouse',31,0) where rowid=recs(j).rowid; end loop; END LOOP; CLOSE c1; end;

Temps dexcution: 20,8s

On remarque lutilisation du RowID permettant dimplmenter lquivalent de la clause CURRENT OF de la version prcdente.
Listing7.16: Version utilisant un curseur BULK COLLECT et un FORALL avec clause WHERE sur le champ Empno
declare Cursor c1 is select empno,sal,loc from bigemp e,bigdept d where e.deptno=d.deptno and loc in ('CHICAGO','Toulouse'); TYPE C1RecTab IS TABLE OF c1%rowtype; Recs C1RecTab; TYPE Table_N IS table OF Number ; lstempno Table_N:=Table_N(); lstnewsalary Table_N:=Table_N() ; TblIidx integer; begin lstempno.extend(1000);lstnewsalary.extend(1000); OPEN c1; LOOP FETCH c1 BULK COLLECT INTO Recs LIMIT 1000; EXIT WHEN c1%NOTFOUND; TblIidx:=1; for j in Recs.first..Recs.last loop lstempno(TblIidx):=Recs(j).empno; if recs(j).loc = 'CHICAGO' then lstnewsalary(TblIidx):=Recs(j).sal+10; else lstnewsalary(TblIidx):=Recs(j).sal+31; end if; TblIidx:=TblIidx+1; end loop;

Chapitre 7

Techniques d'optimisation desrequtes avances 207

forall j in 1..(TblIidx-1) update bigemp set sal=lstnewsalary(j) where empno=lstempno(j); END LOOP; CLOSE c1; end;

Temps dexcution: 11,3s

On remarque un gain de performances assez important avec lintroduction de FORALL. Cependant, si nous regardons le schma dexcution de linstruction UPDATE, nous voyons que lindex PK_BIGEMP est en toute logique mis contribution alors que lhabituelle clause CURRENT OF travaille directement sur les RowID. La version suivante montre le gain apport par le travail direct avec les RowID.
Listing7.17: Version utilisant un curseur BULK COLLECT et un FORALL avec clause WHERE sur le RowID
declare Cursor c1 is select sal,loc,e.rowid from bigemp e,bigdept d where e.deptno=d.deptno and loc in ('CHICAGO','Toulouse'); TYPE C1RecTab IS TABLE OF c1%rowtype; Recs C1RecTab; TYPE Table_N IS table OF Number ; TYPE Table_RowId IS table OF Rowid ; lstnewsalary Table_N:=Table_N() ; lstrowid Table_RowId:=Table_RowId() ; SampleSize integer := 1000; TblIidx integer; begin lstnewsalary.extend(SampleSize);lstrowid.extend(SampleSize); OPEN c1; LOOP FETCH c1 BULK COLLECT INTO Recs LIMIT SampleSize; EXIT WHEN c1%NOTFOUND; TblIidx:=1; for j in Recs.first..Recs.last loop if recs(j).loc = 'CHICAGO' then lstnewsalary(TblIidx):=Recs(j).sal+10; else lstnewsalary(TblIidx):=Recs(j).sal+31; end if; lstrowid(TblIidx):=Recs(j).rowid; TblIidx:=TblIidx+1; end loop; forall j in 1..(TblIidx-1) update bigemp set sal=lstnewsalary(j) where rowid=lstrowid(j); END LOOP; CLOSE c1; end ;

Temps dexcution: 9,57s

208

tude et optimisation desrequtes

Axe 2

Tableau7.2: Rsum des versions et des temps d'excution associs

Mthode SQL UPDATE SQL MERGE SQL UPDATE optimis PL/SQL curseur de base sans WHERE PL/SQL curseur de base avec WHERE PL/SQL select BULK COLLECT PL/SQL select BULK COLLECT plus FORALL sur Empno PL/SQL select BULK COLLECT plus FORALL sur RowID

Temps d'excution (en secondes)


11,32 12,81 9,21 66,07 28,51 20,80 11,30 9,57

Nous constatons une certaine diversit dans les performances, mais lintroduction des techniques BULK COLLECT et FORALL a un effet indniable. On arrive mme avoir des performances proches du SQL optimis en PL/SQL, ce qui nest pas frquent tant donn la nature mme du PL/SQL qui sappuie sur le SQL.
INFO Ces techniques, dites BULK, sont aussi prsentes sur certaines API clientes telles que les prcompilateurs (Pro*C,etc.).

7.4.4

SQL dynamique et BULK

Les mthodes de SQL dynamiques peuvent aussi utiliser les fonctionnalits BULK au moyen des notations suivantes:
FORALL i IN <Intervale> EXECUTE IMMEDIATE USING <tableau>(i); '<Instruction LMD avec des bindings>'

Vous pouvez mme y insrer une clause RETURNING

FORALL i IN tabdept.first .. tabdept.last 'DELETE FROM bigemp WHERE DeptNo = :1 RETURNING Empno INTO :2' USING tabdept(i) RETURNING BULK COLLECT INTO tabempno;

Chapitre 7

Techniques d'optimisation desrequtes avances 209

Dans le cas de curseurs dynamiques, vous pouvez utiliser la syntaxe suivante:


OPEN c FOR <variable contenant un select>; FETCH c BULK COLLECT INTO <tableau>; CLOSE c;

Dans le cas dun utiliser:

SELECT INTO

dynamique de type

BULK COLLECT,

vous pouvez

EXECUTE IMMEDIATE <variable contenant un select> BULK COLLECT INTO <tableau>;

7.4.5

Traitement des exceptions avec FORALL

Il est possible que, lors de lexcution dinstructions LMD, des exceptions soient leves car des contraintes ne sont pas respectes. Le rsultat avec FORALL sera le mme que si on avait utilis un curseur: les lignes qui prcdent lexception sont modifies mais pas celles qui suivent la ligne lorigine de lexception. Ce comportement est parfois acceptable, surtout si vous prvoyez de faire un ROLLBACK. Par contre, si votre objectif est de conserver tout ce qui peut se faire et de tracer ce qui pose problme, la solution standard qui interrompt le traitement nest pas la bonne. Oracle met notre disposition le mot cl SAVE EXCEPTIONS dans linstruction FORALL. Il a pour effet de stocker les exceptions dans un tableau et de lever lexception "ORA24381: Error in Array DML". Cela conduit la situation suivante:

Les exceptions sont disponibles dans le tableau SQL%BULK_EXCEPTIONS. Le nombre dexceptions est accessible par SQL%BULK_EXCEPTIONS.count. La ligne du tableau origine de lexception est dans SQL%BULK_EXCEPTIONS(i).error_index. Le code de lexception est dans SQL%BULK_EXCEPTIONS(i).Error_code.

Pour traiter les exceptions, il faut capturer lexception ORA-24381 et parcourir le tableau SQL%BULK_EXCEPTIONS. Pour capturer une exception, il faut dabord la dclarer dans la section DECLARE au moyen des instructions suivantes:
ex_erreur_dml EXCEPTION; PRAGMA EXCEPTION_INIT(ex_erreur_dml, -24381);

Listing7.18: Exemple de traitement des exceptions


BEGIN forall j in 1..(TblIidx-1) SAVE EXCEPTIONS update bigemp set sal=lstnewsalary(j) where rowid=lstrowid(j); EXCEPTION WHEN ex_erreur_dml THEN NbrErreur := SQL%BULK_EXCEPTIONS.count; DBMS_OUTPUT.put_line(NbrErreur ||' erreurs'); FOR i IN 1 .. NbrErreur LOOP DBMS_OUTPUT.put_line('Erreur: ' || i || ' Index tableau : ' || SQL%BULK_EXCEPTIONS(i).error_index || ' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE)); END LOOP; END;

7.4.6

Utilisation de cache de donnes

Si une procdure comme celles qui utilisent des tables de rfrences risque de rechercher de nombreuses fois les mmes donnes dans les tables, il peut tre pertinent dutiliser les techniques de cache, en stockant une copie de la table ou les donnes rcemment utilises dans une variable tableau de type TABLE. Illustrons cette technique avec le programme ci-aprs qui compte le nombre de commandes de clients situs en France en PL/SQL, volontairement sans utiliser de jointure des fins de dmonstration.
Listing7.19: Version de base
declare NbrCmd Number :=0; Pays varchar(15); begin for c in (select * from cmd where rownum<100000) loop select pays into Pays from clients where noclient=c.noclient; if Pays='France' then NbrCmd:=NbrCmd+1; end if; end loop; dbms_output.put_line('Nbr Cmd = '||NbrCmd); end;

Listing7.20: Version utilisant une variable de cache


declare NbrCmd Number :=0; Pays varchar(15); TYPE Table_A15 IS table OF varchar(15) index by BINARY_INTEGER; CacheClient Table_A15; begin for c in (select * from cmd where rownum<100000) loop if CacheClient.exists(c.noclient) then

Pays:=CacheClient(c.noclient); else select pays into Pays from clients where noclient=c.noclient; CacheClient(c.noclient):=Pays; end if; if Pays='France' then NbrCmd:=NbrCmd+1; end if; end loop; dbms_output.put_line('Nbr Cmd = '||NbrCmd); end;

On peut mme imaginer donner au cache une dure de vie suprieure la procdure en cours, en utilisant des variables de package qui ont pour dure de vie la dure de la session. Dans ce cas, il faut particulirement veiller au problme de validit du cache, car ses donnes risquent de devenir obsoltes. Cette technique peut avoir pour effet doccuper beaucoup de mmoire, car chaque association de valeurs va rester en mmoire et, cela, pour chaque excution de la fonction ou pour chaque session si une variable de package est utilise. Oracle11g apporte une solution complmentaire avec le cache de rsultat de fonction. Elle permet de mmoriser en cache le rsultat dune fonction de faon partage entre les sessions et en limitant les ressources utilises grce un algorithme de type LRU (Least Recently Used). Cette fonctionnalit permet aussi de grer linvalidation des donnes en cache la suite de modifications de table laide de la clause RELIES_ON. Celle-ci est optionnelle et Oracle semble pouvoir sen passer lors de lanalyse du code. Les paramtres de la base RESULT_CACHE_MAX_ SIZE et RESULT_CACHE_MAX_RESULT permettent de grer la mmoire disponible pour le cache de chaque fonction. Par dfaut, chaque fonction peut utiliser au plus 5% de la mmoire de cache de rsultat (RESULT_CACHE_MAX_SIZE) qui est fix quelques pourcents de la taille de la SGA. Si vous prvoyez dutiliser intensment cette fonctionnalit, il faudra probablement ajuster les valeurs de ses paramtres.
Listing7.21: Version utilisant une fonction avec l'option RESULT_CACHE
create or replace function GetPaysClient(pNoClient number) return varchar2 RESULT_CACHE relies_on (clients) is Pays varchar2(15); begin select pays into Pays from clients where noclient=pnoclient; return(Pays); end GetPaysClient; / declare NbrCmd Number :=0; begin for c in (select * from cmd where rownum<100000 order by noclient) loop if GetPaysClient(c.noclient)='France' then NbrCmd:=NbrCmd+1; end if; end loop; dbms_output.put_line('Nbr Cmd = '||NbrCmd); end;

7.4.7

Utilisation du profiling

Le package DBMS_PROFILER permet de tracer lexcution de code PL/SQL et ainsi de connatre, pour chaque ligne de code, le nombre dexcutions et le temps total dexcution. Cette fonction permet de dtecter les points critiques pour amliorer les performances dune procdure. DBMS_PROFILER stocke les rsultats dans une table interrogeable via SQL. Lidal est dutiliser des outils tiers intgrant le profiling qui mettent disposition des rapports comme celui de la Figure7.4.

Figure7.4 Rapport de profiling issu de l'outil PL/SQL Developer d'Allround Automations.

7.4.8

Compilation du code PL/SQL

Depuis de nombreuses versions dOracle, il est possible de compiler le code des procdures stockes que vous dveloppez ainsi que celles qui sont livres en standard. Cependant, cette procdure tait assez complexe jusqu la version11g qui a normment simplifi les choses. De faon standard, le code PL/SQL est interprt par un runtime du noyau, mais il est possible de le compiler afin davoir du code natif la plateforme. Cette opration, si elle napporte pas forcment des gains significatifs, ne peut pas rduire les performances de faon significative. Il convient cependant de ne compiler que ce qui doit ltre. Tout le code excutant du SQL ne subira aucune amlioration. Si votre procdure excute principalement du SQL, il ny a pas dintrt la compiler.

Pour compiler en code natif partir dOracle11g, il suffit de recompiler la procdure en spcifiant le type de code NATIVE.
ALTER PROCEDURE <nomProcedure> COMPILE PLSQL_CODE_TYPE=NATIVE ;

Il faut bien veiller ne pas laisser les informations de dbogage (clause DEBUG) pour tirer parti des gains de performances. Le code compil ne peut pas tre profil ou dbogu. Ltape de compilation native ne devra donc avoir lieu quaprs la mise au point du code.
Listing7.22: Exemple de procdure effectuant des oprations non SQL et pouvant tirer pleinement profit de la compilation (tri bulle d'une table dcroissante)
create or replace procedure TestPerf is TYPE Table_N IS table OF pls_INTEGER INDEX BY pls_INTEGER; Tbl Table_N ; Taille pls_INTEGER :=4000; modified boolean; swap integer; begin -- On rempli le tableau tri en dcroissant for j in 1..taille loop Tbl(j):=taille-j; end loop; -- On tri le tableau loop modified:=false; for j in 1..taille-1 loop if Tbl(j)>Tbl(j+1) then swap:=Tbl(j); Tbl(j):=Tbl(j+1); Tbl(j+1):=swap; modified:=true; end if; end loop; exit when not modified; end loop; end TestPerf;

Cette procdure en code interprt sexcute en 4,8secondes. Aprs la compilation native, elle le fait en 1,9seconde, ce qui constitue un gain notable. La requte suivante permet de connatre le type de code et la prsence dinformations de dbogage de tout le code PL/SQL de lutilisateur.
SELECT * FROM user_PLSQL_OBJECT_SETTINGS ORDER BY TYPE, PLSQL_CODE_TYPE;

Axe 3
Autres pistes doptimisation

8
Optimisation applicative (hors SQL)
En gnral, une application nest pas seulement une base de donnes, mais un applicatif qui utilise une base de donnes. Ct applicatif, certains choix peuvent avoir de grosses rpercussions sur linteraction avec la base de donnes. Nous resterons au fil de ce chapitre assez gnraliste, car les techniques sont propres chaque environnement de dveloppement.

8.1

Impact du rseau sur le modle client/serveur

Si le rseau est peu performant et que lapplication soit de type client lourd, on veillera rduire le nombre de requtes excutes sur le serveur, nombre qui peut rapidement exploser avec des relations matre/dtails. On veillera ne pas ramener des ensembles de donnes entiers sil est possible de les ramener petit petit. Un maximum de filtrages et de regroupements seront faits ct SGBDR afin de limiter les volumes transfrs sur le rseau.

8.2

Regroupement de certaines requtes

Loverhead de lexcution dune requte se dfinit par le temps ncessaire son excution qui nest pas consacr au parcours des donnes cela inclut les changes interprocessus et rseaux, lanalyse,etc. Il est gnralement considr comme faible. Cependant, ce temps peut devenir trs significatif par rapport au temps total sur des

218

Autres pistes doptimisation

Axe 3

requtes simples. Si beaucoup de requtes sont excutes, des problmes de latence peuvent surgir. Lapparition dORM (Object-Relational Mapping) et de framework a contribu mettre ce problme en exergue. Illustrons ce phnomne avec un exemple: imaginons que, dans notre base exemple, nous souhaitions rcuprer les informations relatives un client qui a pass 10commandes de 5articles pris dans notre catalogue de livres. Une solution que pourrait apporter un ORM gnrant des requtes SQL peu performantes se dcomposerait ainsi:

1requte pour rcuprer le client; 1requte pour rcuprer la collection de 10commandes; 10requtes pour rcuprer les 5articles de chacune des commandes; 50requtes pour rcuprer les 50articles commands (sils sont tous diffrents).

Soit 62requtes SQL. Une autre approche, parfois plus efficace, serait:

1requte pour rcuprer le client; 1requte pour rcuprer les commandes; 1requte pour rcuprer les items de commandes joints avec les articles.

Soit 3requtes SQL. Comme souvent lorsquon parle doptimisation, la notion de performance dpend de pas mal de choses. Si lORM utilise des mcanismes de lazy loading, qui permet dattendre le premier accs effectif une donne, il nexcutera pas forcment toutes les requtes. Si lapplication a la capacit de maintenir un cache des objets, les articles resteront en mmoire et ne seront pas extraire chaque fois. Le regroupement de requtes peut conduire dupliquer des donnes et donc gaspiller des ressources. Par exemple, si les mmes articles sont prsents dans plusieurs commandes, la seconde solution va, inutilement, les ramener plusieurs fois. Certaines personnes pensent, tort, que lutilisation dun ORM vite davoir se plonger dans la base de donnes et que tout marchera tout seul. Les ORM nont rien de magique. Leurs atouts sont indniables dans certains environnements, plus discutables dans dautres. Il est impratif de se pencher sur la configuration des ORM

Chapitre 8

Optimisation applicative (hors SQL) 219

pour ne pas tomber dans des travers tels que celui dcrit prcdemment. Les ORM peuvent tout fait gnrer du SQL performant sils sont correctement configurs. Hibernate, par ailleurs, intgre un langage HQL qui permet de faire des requtes performantes dans le SGBDR au lieu de parcourir des collections dobjets quil faudrait pralablement rcuprer. Le problme de la multiplication des requtes arrive aussi dans dautres circonstances. Jai eu plusieurs fois loccasion de voir dans des applications des boucles dans lapplicatif l o une jointure aurait t pertinente. Ci-aprs figure un exemple de code multipliant les requtes inutilement:
$ListeCmd=$db->GetArray("select * from cmd where noclient=$noclient"); foreach($ListeCmd as $cmd) { $LignesCommandes=$db->GetArray("select * from lignes_cmd where nocmd=".$cmd['nocmd']); // Traitement }

8.3

Utilisation du binding

Le binding est un mcanisme qui permet dexcuter plusieurs fois la mme requte en changeant la valeur des paramtres. Sous Oracle, cette technique utilise des paramtres prfixs par le symbole deux points (:). La valeur effective est passe sparment du texte de la requte. Exemple dune requte utilisant un binding sous Oracle:
Select * from clients where Noclient=:P1

Cette technique permet dconomiser le temps danalyse de la requte sur les excutions suivant la premire, ce qui peut tre intressant si une mme requte est utilise de nombreuses fois. Lexemple ci-aprs en PHP montre deux solutions possibles:

La premire modifie le texte de la requte et la re-parse donc chaque fois. La seconde utilise un binding.

Le rsultat est sans appel: on passe de 7,68secondes 1,05seconde soit un facteur7 pour 10000excutions. Sur 1000excutions, le facteur nest plus que de 2,5, ce qui est dj un bon rsultat. Bien videmment, le facteur de gain dpend de la requte excute.

220

Autres pistes doptimisation

Axe 3

Listing8.1: Comparaison de requtes avec et sans binding


<?php $conn = oci_connect('scott', 'tiger', 'orcl'); // Version sans binding $start= microtime (true); for($i=0;$i<10000;$i++) { $query = 'SELECT * FROM clients where noclient='.(14797+$i); $stid = oci_parse($conn, $query); $r = oci_execute($stid, OCI_DEFAULT); $row = oci_fetch_row($stid); oci_free_statement ($stid); } echo microtime (true)-$start; // Version Avec binding $start= microtime (true); $query = 'SELECT * FROM clients where noclient=:client'; $stid = oci_parse($conn, $query); for($i=0;$i<10000;$i++) { $client=14797+$i; oci_bind_by_name ( $stid , 'client', $client ); $r = oci_execute($stid, OCI_DEFAULT); $row = oci_fetch_row($stid); } oci_free_statement ($stid); echo microtime (true)-$start; oci_close($conn); ?>

Dans le cadre de lutilisation de paramtres binds sur des prdicats dintervalles dans une instruction SELECT, les bindings peuvent fausser les estimations car loptimiseur recourt des valeurs prdfinies telles que 5% pour les intervalles ouverts (>x) et 0,25% pour les intervalles borns (>x AND <y) [voir Chapitre5, section5.1.3, "Slectivit, cardinalit, densit"]. Ces estimations pouvant poser des problmes, la version10g a introduit la notion de Bind Peeking qui a pour effet de dterminer le cot en fonction de la premire valeur utilise. Cette solution donne parfois de meilleurs rsultats mais elle a provoqu une leve de boucliers dans la communaut car elle entranait des instabilits du plan dexcution utilis pour une mme requte en fonction de la premire valeur soumise, ce qui avait un aspect alatoire. La version11g a chang de mthode en introduisant les Adaptive Cursors. Cette technique permet de grer plusieurs plans dexcution pour une mme requte utilisant le binding, loptimiseur choisissant ensuite le plan le plus adapt la valeur soumise.

Chapitre 8

Optimisation applicative (hors SQL) 221

8.4

Utilisation de cache local l'application

Plutt que de rinterroger la base de donnes chaque fois quon a besoin dune donne de rfrence, il peut tre plus performant dutiliser un cache local. Comme avec tous les caches, cette solution introduit le problme de la dure de validit des donnes du cache et des ventuels comportements inadquats que cela peut entraner.

8.5

Utilisation du SQL procdural

Parfois, la logique mtier exige invitablement de faire un grand nombre de requtes. Plutt que de coder toute la logique du ct client de lapplication, il peut tre pertinent de la coder avec du SQL procdural (bloc PL/SQL sous Oracle, Transact SQL sous SQL Server). Lavantage de cette solution est que les procdures seront excutes dun seul coup sans quitter le noyau, ce qui rduit loverhead de chaque requte. Les performances sont gnralement au rendez-vous sil y a de nombreuses requtes. Au-del des aspects relatifs aux performances, le SQL procdural est parfois utilis pour implmenter la sparation dun applicatif en plusieurs couches. Dans ce cas, la logique mtier est implmente laide de procdures stockes et de packages.

8.6

Gare aux excs de modularit

Parfois, vouloir trop bien faire, on peut introduire des problmes de performances. Par exemple, dans un souhait de dcouplage de deux applications, vous dcidez de mettre disposition dans une des applications un package PL/SQL permettant de manipuler et dinterroger les donnes. Supposons que ce package contienne les fonctions suivantes:
GetCmdClient(NoClient). GetMontantCmd (NoCmd).

Retourne les commandes dun client.

Retourne le montant dune commande.

Ces fonctions sont adaptes aux oprations pour lesquelles elles ont t dfinies. Cependant, il se peut que les besoins voluent et que linterface ne suive pas. Par exemple, si vous avez besoin de calculer le chiffre daffaires dun client, vous allez appeler GetCmdClient puis GetMontantCmd pour chaque commande. Cette approche

222

Autres pistes doptimisation

Axe 3

sera moins efficace que de faire une requte SQL calculant directement ce chiffre daffaires. De faon gnrale, la manipulation des bases de donnes se prte relativement peu la prsentation dAPI pour agir sur les donnes sous-jacentes. Considrez donc les impacts si vous devez recourir ce genre de mcanisme. Lutilisation de vues (avec les rserves prsentes au Chapitre6, section6.2.4, "Rutilisation de vue") peut tre une solution plus performante que des procdures PL/SQL.

9
Optimisation de linfrastructure
9.1 Optimisation de l'excution du SGBDR

Cette tche est plutt dans le primtre de ladministrateur de la base de donnes, mais nous abordons ici quelques pistes de base. Des dizaines de paramtres sont disponibles pour adapter le comportement des SGBDR. Il faut les manipuler avec beaucoup de prudence car ils peuvent avoir de lourdes consquences seul, un DBA devrait normalement les modifier. Si vous navez pas de DBA, les modules AWR et ADDM tudis au Chapitre4, section4.1.3, "Identifier les requtes qui posent des problmes", pourront vous donner des pistes damlioration.
9.1.1 Ajustement de la mmoire utilisable

La plupart des SGBDR intgrent un paramtre permettant de configurer la quantit maximale de mmoire quils peuvent utiliser. Il faut veiller ce que ces paramtres ntouffent pas le serveur (il ne faut pas swapper ces zones), mais il faut que le SGBDR utilise au mieux la mmoire disponible sur le serveur.

Sous Oracle 10g, le paramtre sga_target peut tre utilis. Sous Oracle 11g, les paramtres memory_target et memory_max_target peuvent tre utiliss. Sous SQL Server, le paramtre max
server memory

peut tre utilis.

Sous MySQL, de nombreux paramtres sont disponibles parmi lesquels: key_ buffer_size, innodb_buffer_pool_size, innodb_additional_memory_pool_ size, innodb_log_buffer_size, query_cache_size.

224

Autres pistes doptimisation

Axe 3

Normalement, sous Oracle et SQL Server, ces paramtres sont automatiquement configurs en fonction de la mmoire disponible au moment de linstallation. la suite dun changement de configuration ou pour des raisons diverses, ils peuvent avoir une valeur inadapte et ainsi sous-utiliser les ressources disponibles du serveur. Jai plusieurs fois eu loccasion de constater chez des clients que la base de donnes manquait de mmoire alors que le serveur avait encore1 ou 2Go de mmoire vive disponible. Le cas le plus rcent tait sur un serveur destin la base de donnes avec 2Go de RAM, la mmoire maximale utilisable tait configure 512Mo alors que 1,5Go aurait t plus adapt.
9.1.2 Rpartition des fichiers

Rpartir les fichiers de donnes, de contrle et de journalisation, sur des disques diffrents amliore gnralement les performances en lecture et en criture. Pour les fichiers de contrle Oracle, cette pratique est recommande pour des raisons de fiabilit. Rpartir les donnes et les index sur des tablespaces qui sont sur des disques diffrents est une bonne pratique assez rpandue.

9.2

Optimisation matrielle

Cette tche est plutt dans le primtre du DBA et de ladministrateur systme, cependant nous allons ici survoler quelques pistes. Un des moyens damliorer les performances est damliorer le matriel utilis pour faire tourner le SGBDR. Cette solution devrait tre envisage seulement lorsque toutes les autres ont t puises (do la localisation de ce chapitre la fin de louvrage). Malheureusement, pour des raisons de simplicit, cest souvent une des premires tre mises en uvre. Nous allons rapidement tudier les impacts de lamlioration des lments cls.
9.2.1 Le CPU

De faon gnrale, lamlioration du CPU aura toujours un rsultat positif, du fait quil est un point de passage systmatique pour toutes les oprations. Cependant, cest rarement le point qui rsoudra les gros problmes de performances moins davoir un trs vieux serveur.

Chapitre 9

Optimisation de linfrastructure 225

Laugmentation du nombre de CPU naura gnralement dimpact significatif que sil y a plusieurs utilisateurs ou des excutions de requtes en parallle.
9.2.2 La mmoire vive (RAM)

La quantit de RAM sur les serveurs de base de donnes est souvent le nerf de la guerre. Cest elle qui permet daugmenter la taille du cache (voir Chapitre1, section1.2.6, "Le cache mmoire"). Il est frquent de voir des systmes avec plusieurs gigaoctets de RAM (les SGBDR sont les plus demandeurs darchitectures 64bits). Lcart de performances entre une requte portant sur un volume de donnes tenant en RAM et une requte ncessitant de nombreux accs disque est norme. Pour mmoire:

Un accs disque moyen est de lordre de 10ms de latence avec un dbit de quelques Mo/s. Un accs RAM est de lordre de quelques nanosecondes avec un dbit de quelques Go/s.

Laugmentation de la RAM est souvent lamlioration matrielle la plus efficace.


9.2.3 Le sous-systme disque

Les donnes viennent des disques et repartent sur les disques une fois quelles sont modifies. Si elles sont trop grosses pour tenir en RAM, les performances du soussystme disque sont critiques. Une premire solution consiste amliorer les performances intrinsques des disques:

vitesse rotation 15000 tours/min; interface haut dbit SCSI/SAS; gros cache interne; disques SSD (Solid State Disk, Flash).

Une autre solution consiste utiliser des systmes RAID. La mise en uvre des techniques de mirroring et de stripping permettra daugmenter les dbits. Certains

226

Autres pistes doptimisation

Axe 3

modes RAID peuvent lgrement dgrader les performances en criture (RAID5) et ne sont donc pas recommands pour les fichiers de journalisation. Une dernire solution, plus simple mettre en uvre, consiste rpartir les donnes sur plusieurs disques (avec ou sans RAID) afin de maximiser les dbits.
9.2.4 Le rseau

Les changes avec un SGBDR sont gnralement composs de trs nombreux petits changes (mme sil peut y en avoir des gros). Le facteur cl ct rseau sera la latence. Sur un LAN (Local Area Network), il ny a gnralement pas de problme, mais lutilisation dune application client/serveur sur un WAN (Wide Area Network) peut trs vite devenir dsastreuse.

Conclusion
Au long de cet ouvrage, nous avons tudi de nombreuses solutions pour rsoudre des problmes de performances. Je tiens, dans cette conclusion, vous rappeler une dernire fois quelques principes. Dans la vie, toute mdaille a son revers:

Souvent une optimisation aura des consquences. Le tout est de savoir si elles sont mineures ou pas par rapport au gain apport. Il faudra chaque fois rflchir aux consquences possibles et savoir si elles sont acceptables pour votre situation. Les consquences peuvent tre de nature diffrente: espace disque supplmentaire requis; ralentissement des critures; ralentissement d'autres requtes; ralentissement de la mme requte avec d'autres valeurs; rduction de la capacit monter en charge; etc.

Certains principes sont formidables sur le papier mais, dans la ralit, ils peuvent dboucher sur des contre-performances. Faites preuve de pragmatisme et dobjectivit. Ayez toujours un regard critique sur ce qui se passe quand vous valuez une optimisation. Il faut toujours avoir en tte que la nature des donnes, les volumes concerns, la diversit des utilisateurs et bien dautres paramtres peuvent dboucher sur des situations autres que celles que nous venons de rencontrer et que cela peut faire mentir les plus belles explications. Cet ouvrage nest pas un grimoire de magie plein de formules, mais un livre qui donne des cls pour comprendre les mcanismes des bases de donnes et les pistes damlioration les plus communes.

228

Optimisation des bases de donnes

Le plus important est que vous dveloppiez, au fil du temps, un talent danalyse, qui vous permettra de comprendre des situations diverses et parfois complexes. Llment le plus important pour optimiser une base de donnes, cest vous. Jespre que ce livre vous aura aid dvelopper votre talent.

Annexes

A
Gestion interne des enregistrements
A.1 Le RowID

Le RowID est une information permettant dadresser un enregistrement au sein de la base de donnes (voir Chapitre1, section1.2.2, "Le RowID"). Le RowID dun enregistrement sobtient en interrogeant la pseudo-colonne rowid et il ressemble cela AAARnUAAGAAASIfAAG. Quand les enregistrements sont dans un mme bloc, les RowID se suivent. Lors des changements de blocs, les trois derniers caractres repartent de AAA, et la partie prcdente du rowid change. On voit ci-aprs un changement de bloc:
SQL> select noclient, nom, prenom, rowid from clients; NOCLIENT NOM PRENOM ROWID ---------- -------------- ----------- -----------------. . . . . 14989 Humphrey Carlos AAARdSAAGAAAGg0ABA 14992 Harry Anna AAARdSAAGAAAGg0ABb 14995 Beckham Bobbi AAARdSAAGAAAGg0ABC 14998 Stone Mos AAARdSAAGAAAGg0ABD 15001 Foster Boyd AAARdSAAGAAAGg0ABe 15004 Iglesias Lance AAARdSAAGAAAGg0ABF 15007 Webb Tia AAARdSAAGAAAGg0ABg 15010 Viterelli Hope AAARdSAAGAAAGg0ABH 15013 Dern Hope AAARdSAAGAAAGg0ABi 15016 Sepulveda Al AAARdSAAgAAAgg1AAA 15019 Marshall Pierce AAARdSAAGAAAGg1AAB 15022 Leoni Donna AAARdSAAGAAAGg1AAC 15025 Navarro Candice AAARdSAAGAAAGg1AAD 15028 Krieger Rip AAARdSAAGAAAGg1AAE

232

Annexes

15031 Waite 15034 Sylvian 15037 Paige . . . . .

Winona Carolyn Curtis

AAARdSAAGAAAGg1AAF AAARdSAAGAAAGg1AAG AAARdSAAGAAAGg1AAH

Le package DBMS_ROWID permet de manipuler et de dcoder ces donnes, comme dans cet exemple:
DECLARE ridtyp NUMBER; objnum NUMBER; relfno NUMBER; blno NUMBER; rowno NUMBER; rid ROWID; infos varchar2(200); tabspace varchar2(200); BEGIN SELECT rowid INTO rid FROM bigemp where empno=52900; dbms_rowid.rowid_info(rid,ridtyp,objnum,relfno,blno,rowno); select t.object_type||' '||t.owner||'.'||t.object_name,ta.tablespace_name into infos,tabspace from sys.dba_objects t,sys.dba_tables ta where t.object_id=objnum and t.owner=ta.owner and t.object_name=ta.table_name; dbms_output.put_line('Type RowID:' || TO_CHAR(ridtyp)); dbms_output.put_line('No Objet :' || TO_CHAR(objnum) ||' - '||infos||' Tablespace:'||tabspace); select file_name into infos from sys.dba_data_files where relative_fno=6 and tablespace_name=tabspace; dbms_output.put_line('Datafile :' || TO_CHAR(relfno) ||' - '||infos); dbms_output.put_line('No Block :' || TO_CHAR(blno)); dbms_output.put_line('No ligne :' || TO_CHAR(rowno)); END;

Le rsultat est le suivant:


Type RowID:1 No Objet :71232 - TABLE SCOTT.BIGEMP Tablespace:BIG_TABLESPACE Datafile :6 - E:\ORACLE\ORADATA\ORCL\BIG_TABLESPACE1 No Block :75965 No ligne :2

A.2

Row Migration et Row Chaining

Nous dtaillons ici les mcanismes de Row Migration et de Row Chaining (voir Chapitre 1, section 1.2.5, "Row Migration et Row Chaining") en les tudiant de faon pratique au moyen de la table suivante:

Chapitre A

Gestion interne des enregistrements 233

CREATE TABLE row_mig_chain_demo ( Cle int PRIMARY KEY, col1 VARCHAR2(4000), col2 VARCHAR2(4000), col3 VARCHAR2(4000), col4 VARCHAR2(4000) );

Cration de deux enregistrements qui tiennent dans le mme bloc


INSERT INTO row_mig_chain_demo (cle,col1) VALUES (1,lpad('A',3000,'X')); INSERT INTO row_mig_chain_demo (cle,col1) VALUES (2,lpad('A',3000,'X')); select t.cle,t.rowid from row_mig_chain_demo t; CLE ROWID --- -----------------1 AAASGpAAHAAAIOnAAA 2 AAASGpAAHAAAIOnAAB

Si on analyse les donnes de cette table:


analyze table ROW_MIG_CHAIN_DEMO compute statistics; SQL> select table_name,num_rows,blocks,empty_blocks,avg_space,chain_cnt,avg_ row_len 2 from sys.user_tables where table_name='ROW_MIG_CHAIN_DEMO';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN ------------------ -------- ------ ------------ ---------- ---------- ----------ROW_MIG_CHAIN_DEMO 2 5 3 6869 0 3009

on constate que, dans Chain_Cnt, il ny a pas de chanage dans cette table. Nous allons agrandir un enregistrement afin que les deux ne puissent plus tenir dans le bloc de 8Ko:
UPDATE row_mig_chain_demo SET col2 = lpad('A',4000,'X') WHERE cle = 1;

Lanalyse des donnes de cette table:


analyze table ROW_MIG_CHAIN_DEMO compute statistics; SQL> select table_name,num_rows,blocks,empty_blocks,avg_space,chain_cnt,avg_ row_len 2 from sys.user_tables where table_name='ROW_MIG_CHAIN_DEMO';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN ------------------ --------- ------ ------------ ---------- ---------- ----------ROW_MIG_CHAIN_DEMO 2 5 3 6059 1 5013

montre que, prsent, Chain_Cnt=1. Il y a donc eu Row Migration. Si on "dfragmente" la table:


alter table row_mig_chain_demo move;

234

Annexes

et quon analyse de nouveau les donnes de la table:


TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN ------------------ -------- ------ ------------ ---------- ---------- ----------ROW_MIG_CHAIN_DEMO 2 5 3 3033 0 5010

on voit que Chain_Cnt revient 0. Il ny a plus de chanage et les donnes sont dans deux blocs distincts, comme le montrent les RowID ci-aprs.
select t.cle,t.rowid from row_mig_chain_demo t; CLE ROWID --- -----------------1 AAASGuAAHAAAIOlAAA 2 AAASGuAAHAAAIOkAAA

Si on agrandit une ligne au point quelle ne puisse plus tenir dans un bloc:
UPDATE row_mig_chain_demo SET col3 = lpad('A',3000,'X') WHERE cle = 1; UPDATE row_mig_chain_demo SET col4 = lpad('A',3000,'X') WHERE cle = 1;

et quon analyse une nouvelle fois les donnes de la table:


TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN ------------------ -------- ------ ------------ ---------- ---------- ----------ROW_MIG_CHAIN_DEMO 2 8 0 4841 1 8016

nous voyons quun chanage rapparat dans la colonne Chain_Cnt. Si on "dfragmente" la table nouveau, il y a toujours un chanage (voir ci-aprs). Cela est d au fait que les donnes ne peuvent pas tenir dans un bloc unique car leur taille est suprieure. Le chanage sera permanent.
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN ------------------ -------- ------ ------------ ---------- ---------- ----------ROW_MIG_CHAIN_DEMO 2 6 2 2688 1 8025

B
Statistiques sur les donnes plus en dtail
Comme nous lavons vu au Chapitre5, section5.1, "Statistiques sur les donnes", les statistiques sont un lment fondamental pour lutilisation du CBO (Cost Based Optimiser). Nous allons tudier ici plus en dtail la nature des statistiques utilises par Oracle.

B.1

Statistiques selon l'ancienne mthode de collecte

Lancienne mthode de collecte des statistiques les stocke dans les tables du dictionnaire de donnes, grce linstruction suivante.
analyze table <NomTable> compute statistics;

Les statistiques sont consultables avec les requtes suivantes:


ListingB.1: Statistiques au niveau de la table
select t.table_name,t.num_rows,t.blocks, t.empty_blocks,t.avg_space,t.chain_ cnt,t.avg_row_len from sys.user_tables t where t.table_name like 'BIG%'; TABLE_NAME ----------BIGDEPT BIGEMP NUM_ROWS BLOCKS EMPTY_BLOCKS --------- ------- -----------400004 1630 0 1400014 10097 0 AVG_SPACE CHAIN_CNT AVG_ROW_LEN ---------- ---------- ----------0 0 22 0 0 44

On y voit le nombre de lignes et de blocs utiliss ainsi que la taille moyenne dune ligne. Ces informations contribuent estimer le nombre dentres/sorties disque.

236

Annexes

ListingB.2: Statistiques au niveau des index


select t.index_name, t.num_rows ,t.blevel, t.leaf_blocks, t.distinct_keys ,t. avg_leaf_blocks_per_key, t.avg_data_blocks_per_key,t.clustering_factor from sys.user_indexes t where t.table_name like 'BIG%';
INDEX_NAME NUM_ROWS BLEVEL LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR ----------------- -------- ------ ---------- ------------ ---------------------- ----------------------- ----------------PK_BIGEMP 1400014 2 3103 1400014 1 1 9502 IS_BIGEMP_DEPT 1400014 2 3298 301920 1 1 38416 PK_BIGDEPT 400004 2 886 400004 1 1 1540 IS_BIGDEPT_LOC 400004 2 1375 400004 1 1 6261

ListingB.3: Statistiques au niveau des colonnes


select t.table_name,t.column_name,t.num_distinct,t.low_value,t.high_value ,t.density,t.num_nulls from sys.user_tab_cols t where t.table_name like 'BIG%' order by t.table_name,t.column_id;
TABLE_NAME COLUMN_NAME NUM_DISTINCT LOW_VALUE HIGH_VALUE DENSITY NUM_NULLS ---------- ------------ ------------ ------------------- ---------------- ---------- ---------BIGDEPT DEPTNO 400004 C10B C40B010129 2,49997E-6 0 BIGDEPT DNAME 4 4143434F554E54494E47 53414C4553 0,25 0 BIGDEPT LOC 5 424F53544F4E 546F756C6F757365 0,2 0 BIGEMP EMPNO 1400014 C24A46 C50201015023 7,14278E-6 0 BIGEMP ENAME 14 4144414D53 57415244 0,0714285 0 BIGEMP JOB 5 414E414C595354 53414C45534D414E 0,2 0 BIGEMP MGR 597824 C24C43 C50201015003 1,67273E-6 100001 BIGEMP HIREDATE 13 77B40C11010101 77BB0517010101 0,07692307 0 BIGEMP SAL 34 C211 C3020F1B 0,02941176 0 BIGEMP COMM 4 80 C20F 0,25 1000010 BIGEMP DEPTNO 301920 C10B C40B01011F 3,31213E-6 0

Ces donnes serviront principalement estimer limpact de chaque condition.

B.2

Statistiques selon la nouvelle mthode de collecte

prsent, il est recommand dutiliser le package DBMS_STATS qui donne un niveau dinformation plus lev. Les statistiques sont stockes dans des tables ddies.
ListingB.4: Statistiques DBMS_STATS sur les tables
select * from sys.user_tab_statistics where table_name='BIGEMP'

Chapitre B

Statistiques sur les donnes plus en dtail 237

Nom champ
TABLE_NAME PARTITION_NAME PARTITION_POSITION SUBPARTITION_NAME SUBPARTITION_POSITION OBJECT_TYPE NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN AVG_SPACE_FREELIST_BLOCKS NUM_FREELIST_BLOCKS AVG_CACHED_BLOCKS AVG_CACHE_HIT_RATIO SAMPLE_SIZE LAST_ANALYZED GLOBAL_STATS USER_STATS STATTYPE_LOCKED STALE_STATS

Valeur
BIGEMP

TABLE 1400014 10097 0 0 0 44 0 0

1400014 27/03/2010 11:00:44 YES NO

YES

238

Annexes

ListingB.5: Statistiques DBMS_STATS sur les index


select * from sys.user_ind_statistics where table_name='BIGEMP'

Nom champ
INDEX_NAME TABLE_OWNER TABLE_NAME PARTITION_NAME PARTITION_POSITION SUBPARTITION_NAME SUBPARTITION_POSITION OBJECT_TYPE BLEVEL LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR NUM_ROWS AVG_CACHED_BLOCKS AVG_CACHE_HIT_RATIO SAMPLE_SIZE LAST_ANALYZED GLOBAL_STATS USER_STATS STATTYPE_LOCKED STALE_STATS

Valeur
PK_BIGEMP SCOTT BIGEMP

INDEX 2 3103 1400014 1 1 9502 1400014

1400014 27/03/2010 11:00:49 YES NO YES

ListingB.6: Statistiques DBMS_STATS sur les colonnes


select * from sys.user_tab_col_statistics t where t.table_name like 'BIG%';

Chapitre B

Statistiques sur les donnes plus en dtail 239

Nom champ
TABLE_NAME COLUMN_NAME NUM_DISTINCT LOW_VALUE HIGH_VALUE DENSITY NUM_NULLS NUM_BUCKETS LAST_ANALYZED SAMPLE_SIZE GLOBAL_STATS USER_STATS AVG_COL_LEN HISTOGRAM

Valeur
BIGEMP EMPNO 1400014 C24A46 C50201015023 7,14278571499999E-7 0 1 27/03/2010 11:00:23 1400014 YES NO 6 NONE

Les tables contenants des statistiques DBMS_STATS sont: DBA_TABLES, DBA_OBJECT_TABLES, DBA_TAB_STATISTICS DBA_TAB_COL_STATISTICS, DBA_TAB_HISTOGRAMS, DBA_INDEXES DBA_IND_STATISTICS, DBA_CLUSTERS, DBA_TAB_PARTITIONS DBA_TAB_SUBPARTITIONS, DBA_IND_PARTITIONS, DBA_IND_SUBPARTITIONS, DBA_PART_COL_STATISTICS, DBA_PART_HISTOGRAMS, DBA_SUBPART_COL_STATISTICS, DBA_SUBPART_HISTOGRAMS Avec leurs dclinaisons USER_* et ALL_* Au-del de loptimisation, certaines de ces statistiques peuvent tre utiles pour prendre en main une base de donnes. En effet, elles aident reprer facilement les plus grosses tables, les colonnes qui ne sont jamais remplies,etc.

240

Annexes

B.3

Histogrammes

Nous dtaillons ici les informations stockes dans les histogrammes tudis au Chapitre5, section5.1.3,"Slectivit, cardinalit, densit".
ListingB.7: Statistiques DBMS_STATS sur les histogrammes de frquence
select endpoint_number-nvl(lag(endpoint_number,1)OVER (ORDER BY endpoint_ number ),0) TailleIntervalle ,endpoint_number, endpoint_value from user_tab_histograms t where table_name='BIGDEPT' and column_name = 'LOC'

La colonne TailleIntervalle est calcule partir des valeurs courante et prcdente du Endpoint. endpoint_value est une reprsentation numrique de la chane de caractres.
TailleIntervalle 99900 99900 99900 99900 404 endpoint_number 99900 199800 299700 399600 400004 endpoint_value 344 300 505 052 090 000 000 000 000 000 000 000 349 350 027 483 572 000 000 000 000 000 000 000 354 400 587 944 790 000 000 000 000 000 000 000 406 405 544 089 997 000 000 000 000 000 000 000 438 413 586 837 071 000 000 000 000 000 000 000

Lhistogramme de distribution coupe les donnes en ntranches gales et dtermine les bornes des tranches.
ListingB.8: Statistiques DBMS_STATS sur les histogrammes de distribution
select endpoint_number, endpoint_value from user_tab_histograms where table_name='BIGDEPT' and column_name = 'DEPTNO';

endpoint_number 0 1 2

endpoint_value 10 1000010 2000020

Chapitre B

Statistiques sur les donnes plus en dtail 241

endpoint_number 3 4 5 6 7 8 9 10

endpoint_value 3000030 4000040 5000040 6000040 7000040 8000040 9000040 10000040

Normalement, le SGBDR dtecte les colonnes sur lesquelles il est pertinent de calculer un histogramme. Cependant, vous pouvez forcer les histogrammes avec l'instruction suivante:
execute dbms_stats.gather_table_stats(user,'bigdept',cascade => true ,estimate_percent =>100,method_opt => 'for all columns size 100');

Cest le SGBDR qui dterminera le type dhistogramme en fonction du nombre de valeurs. Il est possible que votre histogramme forc disparaisse lors de la prochaine collecte automatique des statistiques.

B.4

Facteur de foisonnement (Clustering Factor)

Nous allons tudier ici limpact du facteur de foisonnement. La constitution de la table bigemp a t conscutive la cration squentielle des enregistrements; la table bigemp2 a t cre la suite du tri des donnes par la colonne Ename. Les squences dEmpno sont donc rparties de faon occuper successivement un 1/14 de tables diffrentes1.
create table bigemp2 as select * from bigemp order by ename; alter table bigemp2 add constraint PK_bigemp2 primary key(empno); execute dbms_stats.GATHER_TABLE_STATS('SCOTT','BIGEMP2');

1. Rappel: la table bigemp est 100 000 fois la rptition des 14lignes de la table emp avec des offsets sur les Empno et Deptno.

242

Annexes

ListingB.9: Statistiques des index de cl primaire de bigemp et bigemp2


select t.INDEX_NAME,t.LEAF_BLOCKS,t.DISTINCT_KEYS,t.CLUSTERING_FACTOR from sys.user_ind_statistics t where index_name like 'PK_BIGEMP%'; INDEX_NAME LEAF_BLOCKS -------------------------------- ----------PK_BIGEMP 3103 PK_BIGEMP2 3103 DISTINCT_KEYS ------------1400014 1400014 CLUSTERING_FACTOR ----------------9502 1399950

On voit que lindex sur bigemp a un bon facteur de foisonnement puisquil y a en moyenne trois liens par feuille, alors que le deuxime index a presque autant de liens que denregistrements. Dans ce cas, dans chaque feuille, chaque cl pointe sur un bloc du tas de la table diffrent. Dmonstration par la pratique: cette requte, excute sur les deux tables, met un critre sur Empno pour utiliser lindex et un autre sur la colonne Ename afin de forcer un accs au tas, sinon seul lindex serait utilis vu que nous effectuons un
count(*).
Select count(*) from BigEmp where empno between 10000000 and 20000000 and ename='MILLER';

FigureB.1 Sur table bigemp avec index ayant un faible taux de foisonnement (temps d'excution 160ms).

Chapitre B

Statistiques sur les donnes plus en dtail 243

FigureB.2 Sur table bigemp2 avec index ayant un fort taux de foisonnement (temps d'excution 440ms).

On voit ici limpact dun mauvais Clustering Factor (Timing 3 et Consistent Gets100). Loptimiseur redoute tellement ces rsultats quil nutilise pas lindex ds que le clustering factor est mauvais. Dailleurs, pour obtenir ce plan, nous avons d insrer le hint index_rs dans la requte. Sans cela, loptimiseur choisirait de faire un Full Table Scan qui provoque moins de Consistent Gets (9600) mais un temps dexcution de 1,37seconde.
Select /*+index_rs(e)*/ count(*) from BigEmp2 e where empno between 10000000 and 20000000 and ename='MILLER'

C
Scripts de cration des tables detest bigemp et bigdept
Les tables de test nous permettent deffectuer des tests sur une base simple mais de taille suffisamment importante pour mettre en vidence lintrt des optimisations. La base livre est tlchargeable sur le site de lauteur http://www.altidev.com/ livres.php. Sous Oracle, les bases bigdept et bigemp sont gnres laide des scripts suivants. Ces tables sont fondes sur les tables exemples dOracle prsentes dans le schma SCOTT de la base dexemple mais dupliques 100 000 fois, dans laquelle nous avons introduit quelques valeurs particulires. Je vous conseille de les crer dans un tablespace spar, par exemple un tablespace nomm big_TAbLeSpACe qui aurait une taille de 1Go. Nhsitez pas adapter les tailles votre environnement, pour que cela soit le plus significatif sans que chaque test soit trop long.
ListingC.1: Fichier CreateBig.SQL
-- Cration de la table BigDept Create Table bigDEPT ( DEPTNO Number , DNAME VARCHAR2(14), LOC VARCHAR2(13) ) Tablespace BIG_TABLESPACE ; -- Remplissage de la table begin for i in 0..100000 loop insert into bigdept

246

Annexes

select i*100+deptno, dname, decode(mod(i, 1000),0,'Toulouse',loc) from dept; end loop; commit; end; / -- Ajout de la cl primaire alter table bigDEPT add constraint PK_bigDEPT Primary Key(Deptno); -- Cration de la table BigEmp CREATE TABLE bigEMP ( EMPNO NUMBER , ENAME VARCHAR2(10) NOT NULL CHECK (ename=UPPER(ename)), JOB VARCHAR2(9), MGR NUMBER , HIREDATE DATE, SAL NUMBER(7,2) CHECK (SAL > 500 ), COMM NUMBER(7,2), DEPTNO NUMBER NOT NULL ) Tablespace BIG_TABLESPACE ; -- Insertion des lignes begin for i in 0..100000 loop insert into bigemp select i*1000+empno, ename, job, i*1000+mgr, hiredate, sal, comm, i*100+deptno from emp; end loop; commit; end; / -- Ajout de la cl primaire et des foreign key alter table bigEMP add ( constraint PK_BIGEMP primary key(empno), constraint fk_bigemp_dpt foreign key (deptno) REFERENCES bigdept (deptno), constraint fk_bigemp_emp foreign key (mgr) REFERENCES bigemp (empno) );

Si vous navez pas le schma SCOTT sur votre base Oracle, et donc pas les tables dept et emp, voici le script pour les recrer.
ListingC.2: Fichier CreateEmpDept.SQL
Create Table DEPT ( DEPTNO Number(2,0) constraint PK_DEPT Primary Key, DNAME VARCHAR2(14), LOC VARCHAR2(13));

Chapitre C

Scripts de cration des tables detest bigemp et bigdept 247

Insert into Insert into Insert into Insert into Commit;

DEPT DEPT DEPT DEPT

values values values values

('10','ACCOUNTING','NEW YORK'); ('20','RESEARCH','DALLAS'); ('30','SALES','CHICAGO'); ('40','OPERATIONS','BOSTON');

CREATE TABLE EMP ( EMPNO NUMBER(4) PRIMARY KEY, ENAME VARCHAR2(10) NOT NULL CHECK (ename=UPPER(ename)), JOB VARCHAR2(9), MGR NUMBER(4) REFERENCES emp (empno), HIREDATE DATE, SAL NUMBER(7,2) CHECK (SAL > 500 ), COMM NUMBER(7,2), DEPTNO NUMBER(2) NOT NULL REFERENCES dept (deptno) ); Insert into EMP values (7839,'KING','PRESIDENT',NULL ,TO_ DATE('17/11/1981','DD/MM/YYYY'),5000,NULL,10); Insert into EMP values (7566,'JONES','MANAGER',7839 ,TO_DATE('02/04/1981', 'DD/MM/YYYY'),2975,NULL,20); Insert into EMP values (7698,'BLAKE','MANAGER',7839, TO_DATE('01/05/1981', 'DD/MM/YYYY'),2850,NULL,30); Insert into EMP values (7782,'CLARK','MANAGER',7839 ,TO_DATE('09/06/1981', 'DD/MM/YYYY'),2450,NULL,10); Insert into EMP values (7902,'FORD','ANALYST',7566 ,TO_DATE('03/12/1981', 'DD/MM/YYYY'),3000,NULL,20); Insert into EMP values (7369,'SMITH','CLERK',7902 ,TO_DATE('17/12/1980', 'DD/MM/YYYY'),800,NULL,20); Insert into EMP values (7499,'ALLEN','SALESMAN',7698 , TO_DATE('20/02/1981','DD/MM/YYYY'),1600,300,30); Insert into EMP values (7521,'WARD','SALESMAN',7698 ,TO_DATE('22/02/1981', 'DD/MM/YYYY'),1250,500,30); Insert into EMP values (7654,'MARTIN','SALESMAN',7698 , TO_DATE('28/09/1981','DD/MM/YYYY'),1250,1400,30); Insert into EMP values (7788,'SCOTT','ANALYST',7566 ,TO_DATE('19/04/1987', 'DD/MM/YYYY'),3000,NULL,20); Insert into EMP values (7844,'TURNER','SALESMAN',7698 ,TO_ DATE('08/09/1981','DD/MM/YYYY'),1500,0,30); Insert into EMP values (7876,'ADAMS','CLERK',7788 ,TO_DATE('23/05/1987', 'DD/MM/YYYY'),1100,NULL,20); Insert into EMP values (7900,'JAMES','CLERK',7698 ,TO_DATE('03/12/1981', 'DD/MM/YYYY'),950,NULL,30); Insert into EMP values (7934,'MILLER','CLERK',7782 ,TO_DATE('23/01/1982', 'DD/MM/YYYY'),1300,NULL,10); commit;

D
Glossaire
DBA (DataBase Administrator). Dsigne les personnes qui sont charges de ladministration de la base de donnes. DDL (Data Definition Language). Voir LDD. DML (Data Manipulation Language). Voir LMD. E/S (Entres/Sorties). Dsigne les changes vers le sous-systme de stockage, cest-dire gnralement les disques durs. On peut aussi parler dE/S rseau pour dsigner les changes de donnes vers dautres machines travers le rseau. Entit. Dsigne une table dans la terminologie du modle entit/association. I/O (Input/Output). Voir E/S. Index. Principal objet doptimisation des performances, largement abord dans cet ouvrage. Heap (tas). Type dorganisation des donnes. HOT (Heap Organized Table). Dsigne les tables organises en tas. LDD (langage de dfinition des donnes). Sous-ensemble du SQL couvrant les instructions permettant de modifier les structures des donnes, principalement lesinstructions CREATE, ALTER et DROP. LMD (langage de manipulation des donnes). Sous-ensemble du SQL couvrant les instructions permettant de modifier les donnes, principalement les instructions INSERT, UPDATE et DELETE. LOB. Dsigne les types de grande capacit (Large OBject); ils peuvent tre textuels ou binaires.

250

Annexes

OLAP (OnLine Analytical Processing). Dsigne les bases de donnes dites "analytiques", servant gnralement lanalyse des donnes. Elles contiennent gnralement des donnes issues de bases de donnes OLTP. Elles en diffrent par leur structure, le volume ou le niveau de dtails des informations quelles contiennent. OLTP (OnLine Transaction Processing). Dsigne les bases de donnes dites "transactionnelles", servant gnralement pour le traitement oprationnel des donnes. Oracle RAC (Real Application Cluster). Dsigne lutilisation dOracle sur plusieurs serveurs qui partagent un disque dur. RDBMS (Relational Database Management System). Voir SGBDR. Relation. Dsigne une table dans la terminologie du modle relationnel tel quil a t tabli par Edgar Frank Codd. SGBDR (systme de gestion de base de donnes relationnelle). Dsigne un systme (logiciel) qui permet de grer une base de donnes relationnelle. Table. Structure principale permettant de stocker les donnes dans une base de donnes.

Index
A
Analytique 194 ANALYZE 78 Anti-jointure 156 Autotrace 51 AWR 62

D
Datafile 7 DBMS_APPLICATION_INFO 68 DBMS_MONITOR 68 DBMS_PROFILER 212 DBMS_STATS 78 Dnormalisation 38 Densit 80 Direct Path 198 Donnes, cache de 210 DYNAMIC_SAMPLING 82

B
Binding 219 Buffer cache 13 BULK COLLECT 200

E C
explain plan for 55 Extent 8

Cache de donnes 210 Cache mmoire 13 Cardinalit 80 CBO 16 Cluster 132 Clustered Index 127 Clustering Factor 98 Compilation 212 Compression Index 94 index bitmap 101 LOB 121 Table 119 Consistent Gets 53 CONTAINS 113 CONTEXT 112 CTXCAT 113 Cube Group By 189

F
Facteur de foisonnement 98 Fast Full Scan 57 fonction analytique 194 FORALL 203 Full Table Scan 56

G
Grouping Sets 186

H
Hash Join 58 HAVING 162 Heap 11, 87 Hint 177 Histogramme 83

252

Optimisation des bases de donnes

I
Index 14, 85 bitmap 101 Bitmap Join 108 B*Tree 86 clustered 127 colonnes incluses 97 composite 90 compression 94 fonction 99 full text 113 hints 180 multicolonnes 90 reconstruction 150 Reverse 100 IOT 122

P
PARRALEL QUERY 184 Parsing 15 Partitionnement 135 PCTFREE 118 Physical Reads 53 Plan d'excution 15, 55 PL/SQL 200 compilation 212 Predicate push 154 Profiling 212

Q
Query Rewriting 147 Query Transformation 154

L
LIKE 80, 112 Range Scan 57 Ranking 192 Reconstruction index 150 table 149 requtes, rcriture 153 Rollup Group By 188 Row Chaining 12 RowID 10 Row Migration 12

M
Materialized Views 146 MCD 23 Mdiane 194 mmoire, cache 13 MERGE 195, 196 Merge Join 58 MLD 24 MPD 24

S N
Segment 8 Slectivit 80 SGBDR 6 Skip Scan 57, 91 SQL Access Advisor 66 SQL Trace 67 SQL Tuning Advisor 66 Statistiques 77 tendues 84 Statspack 62 Subquery unesting 154

Nested Loop 57 NOLOGGING 165 Normalisation 33

O
Optimizer goal 17 Or Expansion 154

Index 253

T
Tablespace 7, 118 Tas 11, 87 tkprof 69 Trace Analyzer 71 Transformation de requtes 154 Trigger 198 Typage 25 V$sql 61 View merging 154 Vue matrialise 146

W
WITH 191

U
Unique Scan 57

Rfrence

bases de donnes
Mise en uvre sous Oracle
Cet ouvrage a pour objectif de mettre la porte des dveloppeurs les connaissances utiles loptimisation des bases de donnes. Cette activit est souvent cone aux administrateurs de bases de donnes (DBA) une fois que les projets sont termins, alors que cest au niveau du dveloppement quil faut se pencher sur la problmatique des performances. De manire claire et pragmatique, lauteur expose les diffrentes techniques en les prsentant en situation. Pour chacune delles, il montre laide dun cas concret ce quelle amliore et dans quel contexte elle agit efcacement. En homme du terrain, il les compare et prend parti. Louvrage se fonde pour une grande part sur le systme de bases de donnes Oracle (versions 9i, 10g, 11g Release 1&2), toutefois des parallles sont fait rgulirement avec Microsoft SQL Serveur (versions 2005 et 2008) et MySQL (version 5.1) par le biais dencadrs et de paragraphes ddis. Les techniques prsentes pour ces trois systmes sont communes de nombreux autres SGBDR, le lecteur pourra ainsi appliquer les conseils de ce livre quasiment toutes les bases de donnes relationnelles du march.
TABLE DES MATIRES

Optimisation des

Introduction aux SGBDR Modle relationnel Normalisation, base du modle relationnel Mthodes et outils de diagnostic Techniques doptimisation standard au niveau base de donnes Techniques doptimisation standard des requtes Techniques doptimisation des requtes avances Optimisation applicative (hors SQL) Optimisation de linfrastructure Annexes

propos de lauteur : Laurent Navarro est un dveloppeur dapplication de base de donnes depuis plus de 15 ans. Codirigeant de la socit Altidev, il accompagne des industriels dans le dveloppement dapplications de gestion et dinformatique industrielle.

Programmation

Niveau : Intermdiaire Conguration : Multiplate-forme

Pearson Education France 47 bis, rue des Vinaigriers 75010 Paris Tl. : 01 72 74 90 00 Fax : 01 42 05 22 17 www.pearson.fr

ISBN : 978-2-7440-4156-3

Das könnte Ihnen auch gefallen