1 <?xml version="1.0" encoding="utf-8" ?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
5 <!ENTITY in "<small style='font-size:small'>∈</small>">
6 <!ENTITY notin "<small style='font-size:small'>∉</small>">
11 <html xmlns="http://www.w3.org/1999/xhtml" >
13 <title>Optimisation des opérateurs</title>
15 <meta http-equiv="Content-Type"
16 content="text/html; charset=utf-8" />
17 <meta name="copyright"
18 content="Copyright © 2013 Kim Nguyễn" />
21 <script src="../jquery-2.0.3.min.js" type="text/javascript" ></script>
22 <script src="../libs/raphael-min.js" type="text/javascript" ></script>
23 <!-- Load the library -->
24 <script src="../simpleWebSlides.js" type="text/javascript" ></script>
26 <link rel="stylesheet" href="../simpleWebSlides.css" type="text/css" media="all" />
27 <!-- Load a custom Theme, the class-element marks this style-sheet
28 a "theme" that can be swtiched dynamicaly -->
29 <link class="sws-theme" rel="stylesheet" title="U-Psud style" href="../themes/uPsud.css" type="text/css" />
31 <!-- Customize some templates and initialize -->
33 <script type="text/javascript">
34 SWS.Config['sws-slide-change'] = SWS.Effects.slideChangeFadeOutIn;
35 SWS.Config['sws-object-deactivate'] = SWS.Effects.objectDeactivateFadeOut;
36 SWS.Config['sws-object-activate'] = SWS.Effects.objectActivateFadeIn;
38 //Ensures that we load SWS at the very end, after MathJax has
41 $(window).load(SWS.Presentation.init);
45 <a href="bd03.xhtml" class="sws-previous"/>
46 <div class="sws-slide sws-cover sws-option-nofooter">
47 <h1>Bases de données</h1>
48 <h3>Polytech Paris-Sud</h3>
49 <h3>Apprentis 4<sup>ème</sup> année</h3>
50 <h1>Cours 4 : Optimisation des opérateurs</h1>
51 <a href="mailto:kn@lri.fr">kn@lri.fr</a><br/>
52 <a href="http://www.lri.fr/~kn/">http://www.lri.fr/~kn</a>
56 <div class="sws-slide">
57 <h1>Principe d'évaluation d'une requête</h1>
58 <div style="padding-left:15pt;">
60 <li><i>Parsing</i> de la requête</li>
61 <li>Traduction en arbre
62 d'opérateurs de l'algèbre
63 relationnelle <span class="sws-onframe-1-3"><em>(π,
64 σ, ⨝, … )</em></span></li>
67 <li>Génération de <em>plans
68 d'évaluation</em> <span class="sws-onframe-2-3">(en
69 réordonnant les <em> opérations élémentaires</em>)</span></li>
70 <li>Estimation du <em>coût</em> de chacun des
71 plans <span class="sws-onframe-3-3">(en fonction du <em>coût
72 des opérations élémentaires</em>)</span></li>
73 <li>Choix du plan le plus <em>efficace</em></li>
76 <li>Évaluation du plan choisi</li>
77 <li>(Éventuellement mise à jour des statistiques)</li>
79 <p>Avant de s'intéresser à l'évaluation complète d'une requête,
80 on étudie l'évaluation des opérateurs et leur coût
84 <h1>Algorithmes de jointure</h1>
85 <div class="sws-slide">
86 <h1>Jointure naturelle sur une colonne</h1>
87 <p>Considérons :</p><code> SELECT *
89 WHERE people.pid = role.pid;
91 <p>Opération <em>fondamentale</em> utilisée
92 par <em>toutes</em> les applications BD.<br/>
93 L'AR nous dit que <tt>R &join; S = σ<sub>=</sub>(R x
94 T)</tt>, mais c'est <s>très inefficace</s>, on veut optimiser ce cas!
96 <p>On suppose dans la suite M enregistrements dans R,
97 P<sub>R</sub> enregistrements/page, N enregistrement dans S,
98 P<sub>S</sub> enregistrements/page.
100 <p>On pose pour les exemples: M=1000, N=500, P<sub>R</sub>=120, P<sub>S</sub>=100</p>
101 <p>L'attribut commun est <tt>a</tt>.</p>
102 <p>Le coût est toujours le nombre d'E/S (en ignorant l'écriture
105 <div class="sws-slide">
106 <h1>Jointure itérative simple</h1>
107 <p>On effectue une double boucle imbriquée:</p>
109 for each record <em>r ∈ R</em> do
110 for each record <em>s ∈ S</em> do
111 if <em>r.a = s.a</em> then res += <em>r &join; s</em> #jointure élémentaire de
112 done #2 enregistrements
115 <p>Pour chaque <s>enregistrement</s> de la relation externe (R) on
116 scanne entièrement la relation interne (S)</p>
117 <p>Coût: <em>M + P<sub>R</sub> * M * N</em><br/>
118 Exemple: 1000 + 120*1000*500 = 60 001 000 E/S!</p>
120 <div class="sws-slide">
121 <h1>Jointure itérative page à page</h1>
122 <p>On effectue une double boucle imbriquée:</p>
124 for each page <em>P ∈ R</em> do
125 for each page <em>Q ∈ S</em> do
126 res += <em>P &join; Q</em> #jointure entre 2 pages
127 done # peut être faite de manière simple
130 <p>Pour chaque <em>page</em> de la relation externe (R) on
131 scanne entièrement la relation interne (S)</p>
132 <p>Coût: <em>M + M * N</em><br/>
133 Exemple: 1000 + 1000*500 = 501 000 E/S!<br/>
134 Optimisation: mettre la relation la plus petite à
136 500 + 500*1000 = 500 500
139 <div class="sws-slide">
140 <h1>Jointure itérative avec index</h1>
141 <p>On effectue une double boucle imbriquée:</p>
143 for each record <em>r ∈ R</em> do
144 for each record <em>s ∈ S where r.a = s.a</em> do
145 #l'index doit permettre un accès rapide à la colonne a
146 res += <em>r &join; s</em>
150 <p>On exploite l'existence d'un index sur l'une des relation pour
151 en faire la relation interne.</p>
152 <p>Coût: <em>M + P<sub>R</sub> * M * (coût d'accès index + coût
153 index ↦ données)</em><br/>
154 Plusieurs variantes: B+-tree/Hash-index, groupant/non-groupant,…
157 <div class="sws-slide">
158 <h1>Jointure par bloc (avec pages bufferisées)</h1>
159 <p>On exploite le <i>buffer</i> (de taille B+2 pages, B = 10) de la
160 manière suivante:</p>
162 <li> 1 page du <i>buffer</i> pour l'écriture du résultat</li>
163 <li> 1 page du <i>buffer</i> pour la relation interne (S)</li>
164 <li> B pages du <i>buffer</i> pour la relation externe</li>
167 for each block <em>b of size B ∈ R</em> do
168 for each page <em>Q ∈ S </em> do
169 res += <em>b &join; Q</em> #en utilisant la méthode simple
173 <p>Coût: <em>M + N * ⌈M/B⌉</em><br/>
174 Exemple: 1000 + 500 * 1000/10 = 51 000<br/>
175 Variante: blocs sur R et S
179 <div class="sws-slide">
180 <h1>Jointure par tri-fusion 1/2</h1>
181 <p>Idée: « l'intersection » de deux listes est aisée si les deux
182 listes sont triées</p>
183 <code> <em>sort R on a as Rs</em>
184 <em>sort S on a as Ss</em>
185 r := Rs.next(); #On suppose R et S non vides
186 s := Ss.next(); #Sinon jointure vide directement
187 while Rs and Ss are not empty do
188 while r.a != s.a do <s>#avance jusqu'à trouver la même valeur</s>
189 while <em>r.a < s.a</em> do
190 if Rs.hasNext() then r:= Rs.next() else finished
192 while <em>s.a < r.a</em> do
193 if Ss.hasNext() then s:= Ss.next() else finished
196 val := r.a <s>#on prend la liste des enregistrements
197 #ayant la même valeur d'attribut de jointure</s>
199 while r.a = val do P += r; r:= Rs.next() done
200 while s.a = val do Q += s; s:= Ss.next() done
201 res += <em>P &join; Q</em>
205 <div class="sws-slide">
206 <h1>Jointure par tri & fusion 2/2</h1>
207 <p>Coût: M·log<sub>2</sub> M + N·log<sub>2</sub> N + M + N<br/>
208 Exemple: 1000* (1+log<sub>2</sub> 1000) + 500 *
209 (1+log<sub>2</sub> 500) = 15492
211 <p>Le tri n'est pas toujours nécessaire:</p>
213 <li>si on a un index de type B+-tree sur l'attribut de
214 jointure (pour l'une des relations)</li>
215 <li>si R ou S (ou les deux) sont déjà le résultat de tris
216 (<tt>ORDER BY</tt>)</li>
219 <div class="sws-slide">
220 <h1>Jointure par hachage</h1>
221 <p>On choisit une fonction de hachage <tt>h</tt> et on
222 partitionne R selon <tt>h(r.a)</tt> pour obtenir K partitions</p>
224 partitionne S selon <tt>h(s.a)</tt> pour obtenir K
226 <p style="text-align:center"><img style="width:60%"
227 src="hash_join.svg"/></p>
228 <p>K choisi en fonction de la taille du <i>buffer</i><br/>
229 Coût: 2(M+N) + M+N (pourquoi ?)</p>
231 <div class="sws-slide">
232 <h1>Jointures généralisées</h1>
234 <li>Égalité sur plusieurs attributs (<tt>R.a = S.a AND R.b =
237 <li>Jointure itérative par index: on peut créer un index
238 pour S sur (a,b) ou utiliser des indexes existants sur l'un
240 <li>On peut aussi utiliser jointure par tri-fusion et
241 hachage en utilisant (a,b) comme clé de tri/hachage</li>
244 <li>conditions d'inégalité:
246 <li> Pour les jointures par index, il faut un arbre
247 B+ <em>groupant</em> (sinon sur-coût pour aller chercher les
250 <li>Jointure par tri-fusion et hachage impossible</li>
251 <li>Jointure itérative par bloc est la meilleure option en général</li>
256 <h1>Autres opérateurs</h1>
257 <div class="sws-slide">
259 <p><em>Taux de sélectivité</em> d'une condition φ (ou d'une
260 requête) pour une relation donnée:</p>
261 <p style="text-align:center"> <span style="border-bottom-style: solid;
262 border-width: 1pt ; border-color:black;"><tt># d'enregistrement
263 sélectionnés</tt></span><br/>
264 <tt>#d'enregistrements</tt></p>
265 <p>Le choix de certains algorithmes dépend de la
267 <p>On ne connaît la « vraie » valeur de la
268 sélectivité <em>qu'après</em> avoir évalué la requête</p>
269 <p>On utilise des statistiques sur les relations pour tenter une
270 <em>approximation</em> du taux de sélectivité</p>
272 <div class="sws-slide">
273 <h1>Statistiques sur les relations </h1>
274 <p>Le SGBD conserve, entre autres, les statistiques
275 suivantes pour chaque relations R:</p>
276 <ul><li>Nombre d'enregistrements (<tt>N</tt>), taille d'un
277 enregistrement, nombre d'attributs/page (<tt>P</tt>)</li>
278 <li>Nombre de pages de la relation (les pages ne sont pas
279 toutes remplies de manière optimale)</li>
280 <li><tt>V(a)</tt> : nombre de valeurs distinctes pour l'attribut <tt>a</tt>
281 (dans la relation R)</li>
282 <li>Estimation de sélectivité pour l'attribut <tt>a</tt>: <tt>V(a)/N</tt></li>
283 <li>Profondeur pour les arbres B+</li>
284 <li>Nombre de page pour les feuilles d'un arbre B+</li>
285 <li>Nombre de valeurs distinctes pour la clé de recherche d'un index</li>
288 <div class="sws-slide">
290 <p>Sélection simple, égalité avec une constante : Scan ou
291 Index (si groupant)</p>
292 <p>Sélection simple avec index non groupant : Index + <em>tri des
293 adresses de pages</em>, parcours ordonné. Très efficace si
294 l'ensemble des adresses à trier tiens en mémoire</p>
295 <p>Sélection généralisés, deux approches:</p>
297 <li>On choisit une sous-condition (qui concerne le moins de
298 pages = la plus sélective) et on applique les autres
299 sous-conditions au résultat intermédiaire</li>
300 <li>Si on a deux sous-conditions « <tt>AND</tt> » avec 2 indexes (types 2 ou 3)
301 séparés, calcul des ensembles de <tt>rid</tt> et intersection
302 des résultats. On applique ensuite les autres critères.
306 <div class="sws-slide">
307 <h1>Résultat trié/élimination des doublons</h1>
308 <p>Plusieurs techniques :</p>
310 <li>Utilisation d'un index (type B+-tree) si groupant ou si
311 coût d'accès au données « raisonnable » (résultat dans l'index
312 ou peu de résultats + accès aux données) </li>
313 <li>Utilisation d'un tri explicite après calcul des résultats
314 (+ élimination des doublons durant la phase de tri)
318 <div class="sws-slide">
320 <p>On parle ici de la projection, <em>π</em> de l'algèbre
321 relationnelle, donc avec élimination des doublons : </p>
322 <code> SELECT <em>DISTINCT</em> a,b FROM t </code>
325 <li>Si index sur <tt>(a,b)</tt> disponible, utilisation
326 directe de l'index</li>
327 <li>Sinon tri et projection durant la phase de tri</li>
328 <li>Double partitionnement par hachage</li>
331 <div class="sws-slide">
332 <h1>Double partitionnement</h1>
333 <p>Repose sur l'utilisation de <em>deux</em> fonctions de hachage
334 <tt>h</tt> et <tt>g</tt> <s>distinctes</s></p>
336 <li>On partitionne R en K partitions en
337 utilisant <tt>h</tt></li>
338 <li>En suite pour chaque partition entre 1 et K, on crée une
339 table de hachage en mémoire (avec <tt>g</tt> comme fonction)
340 pour pour éliminer les doublons de la partition</li>
342 <p style="text-align:center;"><img src="hash_partition.svg"/></p>
343 <p>Permet d'effectuer « <tt>DISTINCT</tt>» sans tri! </p>
345 <div class="sws-slide">
346 <h1>Opérations ensemblistes</h1>
348 <li>Intersection et produit cartésien: cas dégénérés de
349 jointure (comment?)</li>
350 <li><tt>UNION DISTINCT</tt> et <tt>EXCEPT</tt> sont
351 similaires. 2 approches:
352 <ol> <li>Par tri. On tri les deux relations sur tous les
353 attributs et on fusionne en éliminant les doublons. Résultat
355 <li>Par hachage. Technique du double partitionnement. On
356 partitionne R et S avec <tt>h</tt>. Pour chaque partition
357 de S et R, on ajoute les éléments dans une table H, en
358 éliminant les doublons</li>
363 <div class="sws-slide">
364 <h1>Opérations d'agrégat</h1>
366 <li>Sans <tt>GROUP BY</tt>:
367 <ul><li>En général, il faut faire un scan de la
369 <li>Si les attributs agrégés sont dans un index, on peut
370 faire un scan d'index uniquement (en espérant que l'index
371 est plus petit)</li></ul>
373 <li>Avec <tt>GROUP BY</tt>: identique au cas sans <tt>GROUP
374 BY</tt> mais tri préalable pour déterminer les groupes, et
375 scan « groupe par groupe » pour calculer la fonction
380 <div class="sws-slide">
382 <p>L'algèbre relationnelle <em>est simple</em> (quelques opérateurs pour
383 exprimer l'ensemble des requêtes)</p>
384 <p>Chaque opérateur peut être réalisé de <em>plusieurs manières</em>
385 différentes, avec <em>différents compromis</em></p>
386 <p>Tout cela est encore complexifié quand on considère les
387 <em>compositions d'opérateurs</em> (prochain cours)</p>
388 <p>Tout est encore plus complexifié si on considère que le SGBD
389 gère plusieurs requêtes en parallèle (hors programme)</p>
390 <p>En pratique, <em>une part importante</em> du moteur de
391 requête des SGBD est l'implantation <em>d'heuristiques</em> pour
392 faire les meilleurs choix (ou plutôt, les moins pires).</p>