hotel (noms,nomh,categorie,adresse,tel,nb_chambres) station (noms,gare) activite (type_activite,noms)Pour chacune des requêtes suivantes, on demande:
SELECT adresse, tel, nb_chambres FROM hotel WHERE noms='pesey' AND categorie=3;(1) arbre syntaxique de la requête : Figure 9.1
SELECT noms, gare FROM station, activite WHERE type_activite = ``tennis'' AND station.noms=activite.nomsarbre syntaxique de la requête: Figure 9.1
| cout(station Temp) = | { { { { { { { { |
|
./figures/q12_arbre_syntaxique.eps
Figure 9.1 : Arbres Syntaxique et Restructuration Algébrique pour les requêtes (1) et (2)
CREATE TABLE FILM ( CREATE TABLE VU (
TITRE VARCHAR2(32), SPECTATEUR VARCHAR2(32),
REALISATEUR VARCHAR2(32), TITRE VARCHAR2(32)
ACTEUR VARCHAR2(32) );
);
Soit la requête SQL:
SELECT ACTEUR, REALISATEUR
FROM FILM, VU
WHERE FILM.TITRE=VU.TITRE
Dans chacun des cas suivants, donner l'algorithme de jointure de
ORACLE (par EXPLAIN, un arbre d'exécution commenté, une
explication textuelle ou tout autre moyen de votre choix):
Plan d'exécution
------------------------------------------------------------------------
0 SELECT STATEMENT
1 MERGE JOIN
2 SORT JOIN
3 TABLE ACCESS FULL VU
4 SORT JOIN
5 TABLE ACCESS FULL FILM
fi-optim2.ps
Figure 9.3 : Plan d'exécution
CREATE INDEX FILM_TITRE_idx on FILM (TITRE);
Plan d'exécution
------------------------------------------------------------------------
0 SELECT STATEMENT
1 NESTED LOOPS
2 TABLE ACCESS FULL VU
3 TABLE ACCESS BY ROWID FILM
4 INDEX RANGE SCAN FILM_TITRE_IDX
CREATE INDEX FILM_TITRE_idx on FILM (TITRE);
CREATE INDEX VU_TITRE_idx on VU (TITRE);
Plan d'exécution
-----------------------------------------------------------------------
0 SELECT STATEMENT
1 NESTED LOOPS
2 TABLE ACCESS FULL VU
3 TABLE ACCESS BY ROWID FILM
4 INDEX RANGE SCAN FILM_TITRE_IDX
SELECT e.enom, d.dnom
FROM emp e, dept d
WHERE e.dno = d.dno
AND e.sal = 10000
sur la relation EMP de schéma (EMPNO, SAL, MGR, DNO). Cette
requête affiche le nom des employés dont le salaire (SAL) est égal
à 10000, et celui de leur département. Indiquez le plan d'exécution
dans chacune des hypothèses suivantes.
fi-optim3.ps
Figure 9.4 : Plan d'exécution
Plan d'execution
--------------------------------------------------------------------------
0 SELECT STATEMENT
1 NESTED LOOPS
2 TABLE ACCESS BY ROWID EMP
3 INDEX RANGE SCAN EMP_SAL
4 TABLE ACCESS BY ROWID DEPT
5 INDEX UNIQUE SCAN DEPT_DNO
Boucles imbriquées (NESTED LOOP) : on choisit de parcourir un
sous-ensemble de EMP en utilisant l'index, puis on accède a DEPT
avec l'index sur DEPTNO.
fi-optim8.ps
Figure 9.5 : Plan d'exécution
Plan d'execution
--------------------------------------------------------------------------
0 SELECT STATEMENT
1 NESTED LOOPS
2 TABLE ACCESS FULL DEPT
3 TABLE ACCESS BY ROWID EMP
4 INDEX RANGE SCAN EMP_SAL
Algorithme de SCAN-INDEX. Equivalent à une jointure par NESTED-LOOP
brutal. On pourrait (i) changer l'ordre des tables sans modifier la
complexité, et (ii) faire un tri-fusion.
fi-optim4.ps
Figure 9.6 : Plan d'exécution
Plan d'execution
--------------------------------------------------------------------------
0 SELECT STATEMENT
1 NESTED LOOPS
2 TABLE ACCESS FULL DEPT
3 TABLE ACCESS BY ROWID EMP
4 AND-EQUAL
5 INDEX RANGE SCAN EMP_DNO
6 INDEX RANGE SCAN EMP_SAL
Comme l'index sur EMP(DNO) n'est pas unique, on a intérêt à limiter
la liste des adresses de tuples en utilisant les deux index
et en faisant l'intersection.
SELECT e.enom
FROM emp e, dept d
WHERE e.dno = d.dno
AND d.ville = 'Paris'
Plan d'execution
--------------------------------------------------------------------------
0 SELECT STATEMENT
1 MERGE JOIN
2 SORT JOIN
3 TABLE ACCESS FULL DEPT
4 SORT JOIN
5 TABLE ACCESS FULL EMP
Algorithme de tri-fusion classique.
SELECT e.enom
FROM emp e
WHERE e.dno IN (SELECT d.dno
FROM Dept d
WHERE d.Ville = 'Paris')
Voici le plan d'exécution donné par ORACLE :
0 SELECT STATEMENT
1 MERGE JOIN
2 SORT JOIN
3 TABLE ACCESS FULL EMP
4 SORT JOIN
5 VIEW
6 SORT UNIQUE
7 TABLE ACCESS FULL DEPT
Qu'en dites vous ?
Création d'une table temporaire (VIEW) contenant les numéros
des départements à Paris. On a éliminé les doublons (SORT
UNIQUE). Ensuite on fait un tri-fusion. Donc exécution différente
pour une requête équivalente.
SELECT *
FROM EMP X WHERE X.SAL IN (SELECT SAL
FROM EMP
WHERE EMP.EMPNO=X.MGR)
Cette requête cherche les employés dont le salaire (SAL) est égal
à celui de leur patron (MGR). On donne le plan d'exécution avec
Oracle (outil EXPLAIN) pour cette requête dans deux cas: (i) pas
d'index, (ii) un index sur le salaire et un index sur le numéro
d'employé. Expliquez dans les deux cas ce plan d'exécution
(éventuellement en vous aidant d'une représentation arborescente de
ce plan d'exécution).
Plan d'exécution ------------------------------------------------------------------------ 0 FILTER 1 TABLE ACCESS FULL EMP 2 TABLE ACCESS FULL EMPFigure 9.7.
Boucles imbriquées (FILTER) : On parcourt la table EMP (ligne 2); pour chaque employé, on regarde le salaire SAL et le numéro du patron MGR; on parcourt alors la table EMP (ligne 3) pour trouver l'employé dont le numéro est MGR et on compare le salaire à SAL. Donc c'est une boucle imbriquée brutale : on aurait pu faire un tri-fusion.fi-optim6.ps
Figure 9.7 : Plan d'exécution
Plan d'exécution
------------------------------------------------------------------------
0 FILTER
1 TABLE ACCESS FULL EMP
2 AND-EQUAL
3 INDEX RANGE SCAN I-EMPNO
4 INDEX RANGE SCAN I-SAL
Figure 9.8.
Boucles imbriquées (FILTER) : on parcourt la table EMP (ligne 2). Pour chaque employé, le salaire SAL et le numéro EMPNO, valeur de l'attribut MGR servent de clé pour accéder à l'index (lignes 4 et 5). L'intersection des listes de row-id (ligne 3) obtenues par les étapes 4 et 5 donne si elle est non vide un row-id de patron ayant même salaire que l'employéfi-optim7.ps
Figure 9.8 : Plan d'exécution
SELECT *
FROM EMP X
WHERE X.SAL = (SELECT SAL
FROM EMP
WHERE EMP.EMPNO=X.MGR)
on a le plan d'exécution suivant:
Plan d'exécution
------------------------------------------------------------------------
0 FILTER
1 TABLE ACCESS FULL EMP
2 TABLE ACCESS ROWID EMP
3 INDEX RANGE SCAN I-EMPNO
Expliquez-le.
Dans ce cas, seul l'index sur les numéros d'employés est utilisé.
Boucles imbriquées (FILTER); on parcourt la table EMP: pour chaque
employé, l'attribut MGR donne le numéro d'employé de son patron.
On accède à son patron par l'index sur les numéros d'employé (lignes
4 puis 3): on vérifie alors si son salaire est égal à celui de
l'employé.
SELECT F.TITRE
FROM SEANCE S, FILM F, ARTISTE A
WHERE A.NOM = 'Hitchcock'
AND F.ID-REALISATEUR = A.ID-REALISATEUR
AND S.ID-FILM = F.ID-FILM
AND S.HEURE_DEBUT > '20:00'
0 SELECT STATEMENT
1 MERGE JOIN
2 SORT JOIN
3 NESTED LOOPS
4 TABLE ACCESS FULL ARTISTE
5 TABLE ACCESS BY ROWID FILM
6 INDEX RANGE SCAN IDX-ARTISTE-ID
7 SORT JOIN
8 TABLE ACCESS FULL SEANCE
Commentez le plan donné par EXPLAIN. Pourrait-on améliorer les
performances de cette requête?
L'existence d'un tri-fusion indique qu'il manque un index. Ici on
peut résoudre le pb en créant un index sur SEANCE(id-Film).
CREATE TABLE Artiste ( CREATE TABLE Film (
ID-artiste NUMBER(4), ID-film NUMBER(4),
Nom VARCHAR2(32), Titre VARCHAR2(32),
Adresse VARCHAR2(32) Année NUMBER(4),
); ID-réalisateur NUMBER(4)
);
CREATE TABLE Joue (
ID-artiste NUMBER(4),
ID-film NUMBER(4)
);
Questions:
SELECT nom, titre FROM artiste, film, joue WHERE artiste.ID-artiste = joue.ID-artiste AND film.ID-film = joue.ID-film
0 SELECT STATEMENT
1 MERGE JOIN
2 SORT JOIN
3 NESTED LOOPS
4 TABLE ACCESS FULL JOUE
5 TABLE ACCESS BY ROWID ARTISTE
6 INDEX UNIQUE SCAN ARTISTE_IDX
7 SORT JOIN
8 TABLE ACCESS FULL FILM
Comme il n'y a qu'un seul index utilisable, on fait un parcours
séquentiel sur Joue pour utiliser l'index le plus tôt possible,
puis on fait un tri fusion. On peut aussi faire le parcours
séquentiel initial sur Film. Petit piège : l'index sur
ID_réalisateur n'est pas utilisable pour la jointure.
0 SELECT STATEMENT
1 NESTED LOOPS
2 NESTED LOOPS
3 TABLE ACCESS FULL ARTISTE
4 TABLE ACCESS BY ROWID JOUE
5 INDEX RANGE SCAN JOUE_ARTISTE
6 TABLE ACCESS BY ROWID FILM
7 INDEX UNIQUE SCAN FILM_IDX
Comme il y a une seule table (ARTISTE) sans index propre à la
jointure, on la choisit pour effectuer le parcours séquentiel
initial.
0 SELECT STATEMENT
1 MERGE JOIN
2 SORT JOIN
3 NESTED LOOPS
4 TABLE ACCESS FULL JOUE
5 TABLE ACCESS BY ROWID FILM
6 INDEX UNIQUE SCAN FILM_IDX
7 SORT JOIN
8 TABLE ACCESS FULL ARTISTE
Les index existant ne peuvent servir qu'à une seule jointure :
celle entre JOUE et FILM. Donc il ne reste que la solution de
faire un TRI-FUSION pour la jointure avec ARTISTE. NB : on
parcours JOUE puis on accède à FILM par l'index. On pourrait
faire le contraire (parcourir FILM et accéder à JOUE). Quand il
a des statistiques, le SGBD choisit la plus petite des tables
pour le parcours séquentiel.