Bonsoir,
je fais des tests simples pour en apprendre plus sur plans d'exécution/optim,etc... Et je tombes sur un cas qui me semble curieux (mais je ne suis pas sûr de ma compréhension des plans d'exécution suivants) :
Je possède deux tables de tests :
- modele (id_modele varchar2(20), libelle_modele(varchar2(20)))
=> dont le champ id_modele varchar2(20) est la PK
- vehicule (id_vehicule number(3), id_modele (varchar2(20), libelle_vehicule(varchar2(20))))
=> qui possede une fk sur la table modele via le champ id_modele

Un index est donc créé pour la PK de la table modele et autre pour la FK de la table vehicule... (j'utilise une clé varchar2 pour simuler une clé naturelle)

J'insere dans ma table "modele" 23 modeles fictifs de véhicules.
J'insère dans ma table "vehicule" 284 véhicules fictifs qui pointent aléatoirement sur un des 30 modèles créés précédemment.

Je lance la commande suivante dans l'espoir de collecter des stats fraîches :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
 
begin  
	DBMS_STATS.GATHER_DATABASE_STATS();  
end;  
/
Je fais une jointure simple de ce type :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
 
 select m.libelle_modele,v.id_modele
from vehicule v, modele m
where m.id_modele = v.id_modele;
Le plan pour cette requête donne :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
--------------------------------------------------------------------------
| Id  | Operation          | Name            | Rows  | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------
|   0 | SELECT STATE.. |                 |    22 |  2750 |    7  (15)| 00:0|
|*  1 |  HASH JOIN         |                 |    22 |  2750 |     7  (15)| 00: |
|   2 |   TABLE ACCESS FULL| MODELE |    23|   782 |     3   (0)| 00:0
|   3 |   TABLE ACCESS FULL| VEHICULE |   284 | 25844 |     3   (0)| 00:0
--------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - access("M"."ID_MODELE"="V"."ID_MODELE")
 
 
Statistiques
----------------------------------------------------------
          8  recursive calls
          0  db block gets
         18  consistent gets
          0  physical reads
          0  redo size
       5080  bytes sent via SQL*Net to client
        396  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         23  rows processed
Je me dis que l'optimiseur à jugé qu'il était inutile d'utiliser l'index et qu'un acces full scan était le plus optimal...
(Mais à quoi correspond l'utilisation du hash join dans ce cas ?)

Je change la requête ainsi :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
 
 select v.id_vehicule,
	(select m.libelle_modele from modele m where m.id_modele = v.id_modele)
from vehicule v;
et maintenant le résultat devient :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
 
| Id  | Operation         | Name            | Rows  | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------|   0 | SELECT STATEMENT  |                 |   284 | 25844 |     3   (0)| 00:00
|*  1 |  INDEX RANGE SCAN | FK_ID_MODELE  |     1 |    20 |     1   (0)| 
|   2 |  TABLE ACCESS FULL| VEHICULE |   284 | 25844 |     3   (0)| 00:00
--------------------------------------------------------------------------
 
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - access("M"."ID_MODELE"=:B1)
 
Statistiques
----------------------------------------------------------
          8  recursive calls
          0  db block gets
         18  consistent gets
          0  physical reads
          0  redo size
       5080  bytes sent via SQL*Net to client
        396  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         23  rows processed
Sauriez-vous répondre à ces questions :
Pourquoi le côut est-il moins élevé dans ce cas (divisé par 2)?
Pourquoi l'optimiseur n'a-t-il pas utilisé l'index via un range scan dans la première requête?

Merci d'avance pour votre aide,
Lek.