Les caprices de l'optimiseur oracle- ?
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:
1 2 3 4 5
|
begin
DBMS_STATS.GATHER_DATABASE_STATS();
end;
/ |
Je fais une jointure simple de ce type :
Code:
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:
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:
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:
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.