Académique Documents
Professionnel Documents
Culture Documents
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
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.
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
154
Axe 2
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
Chapitre 6
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'
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
Avec index
MyISAM
Jointure
Sous-requte
Jointure
Sous-requte
Temps
12,89s
13,53s
0,01s
13,53s
5242448
5243442
158
5243442
Jointure
Sous-requte
Temps
3,48s
13,51s
Reads
3700
2606480
Key_read_requests
InnoDB
Avec index
Oracle
Jointure
Sous-requte
Jointure
Sous-requte
Temps
6,15s
8,75s
0,01s
0,60s
Consistent Gets
8336
4891735
807
12175
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
156
Axe 2
Avec index
MS SQL Server
Jointure
Sous-requte
Temps
0,625s
0,046s
35,27
60,44
Estimated Cost
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)
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
Chapitre 6
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
Avec index
Anti-jointure
Sous-requte
Anti-jointure
Sous-requte
10,11s
10,11s
0,02s
0,02s
29850364
29850364
2974
2974
Anti-jointure
Sous-requte
Temps
24,31s
25,34s
Reads
2976
5948
Temps
Key_read_requests
Avec index
Oracle
Anti-jointure
Sous-requte
Anti-jointure
Sous-requte
Temps
0,340s
2,282s
0,375s
0,031s
6976
113419
5522
8909
Consistent Gets
MS SQL Server
Temps
Estimated Cost
Sans index
Avec index
Anti-jointure
Anti-jointure
2,437s
0,079s
47,49
0,54
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
158
Axe 2
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
Exists
Count
Temps
0,020s
1,110s
Key_read_requests
11915
166782
InnoDB
Exists
Count
Temps
22,940s
29,590s
Reads
8900
2606477
Oracle
Exists
Count
Temps
0,031s
0,031s
Consistent Gets
8909
8909
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
Chapitre 6
MS SQL Server
Exists
Count
Temps
0,062s
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
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
In
Exists
Temps
14,010s
15,340s
Key_read_requests
5243442
5242448
InnoDB
In
Exists
Temps
7,420s
8,200s
Reads
2606480
5212684
Oracle
In
Exists
Forage index
Temps
8,594s
8,594s
4,234s
Consistent Gets
4891735
4891735
2462067
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
160
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
Forage index
0,625s
0,046s
Comme sous Oracle, nous devons forcer lutilisation de lindex avec le hint
WITH
(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);
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.
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
Chapitre 6
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
Grosse requte
MyISAM
Jointure
Expression
sous-requte
Jointure
Expression
sous-requte
Temps
5,890s
0,160s
6,810s
1,950s
Reads
4873397
736
4873397
564513
Petite requte
Grosse requte
InnoDB
Jointure
Expression
sous-requte
Jointure
Expression
sous-requte
Temps
0,670s
0,670s
3,580s
4,030s
Reads
1001449
1000175
2264285
1632143
Petite requte
Grosse requte
Oracle
Jointure
Expression
sous-requte
Jointure
Expression
sous-requte
Temps
0,390s
0,060s
1,48s
1,51s
Consistent Gets
11490
3316
11490
117464
Petite requte
Grosse requte
MS SQL Server
Jointure
Expression
sous-requte
Jointure
Expression
sous-requte
Temps
0,125s
0,109s
0,812s
0,953s
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro
162
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'
MyISAM
Having
Where
Temps
0,080s
0,030s
Reads
91109
45950
InnoDB
Having
Where
Temps
0,090s
0,050s
Reads
91132
45960
Oracle
Having
Where
Temps
0,047s
0,015s
Consistent Gets
624
624
MS SQL Server
Having
Where
Temps
0,046s
0,046s
2010 Pearson Education France Optimisation des bases de donnes Laurent Navarro