IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Oracle Discussion :

Jointure simple qui ne passe pas par les index ?!


Sujet :

Oracle

  1. #1
    Membre régulier Avatar de souch
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2003
    Messages : 145
    Points : 124
    Points
    124
    Par défaut Jointure simple qui ne passe pas par les index ?!
    Bonjour à tous,

    je débarque sous Oracle (pas facile ) et tente de passer une appli de firebird ) à Oracle 10g, en commençant mes tests, je fais direct une syncope en voyant le temps requis pour une requête toute bête sur de petites tables ...

    J'ai certainement fait une erreur grosse comme un éléphant quelque part, voici donc la structure des mes deux tables, ainsi que la requête incriminée :

    Temps d'exécution : entre 0.35s et 0.60s en local sur le serveur via Sql developer.

    Table E_Examens (27500 lignes)
    PrimaryKey integer (number(*,0) sur E_EXAMENS.IDEXAMEN
    index integer (number(*,0) sur E_EXAMENS.IDPATIENT
    index Asc timestamp(0) sur E_EXAMENS.DateExamen
    ForeignKey (Cascade) sur p_patients.idpatient

    Table P_Patients (20000 lignes)
    PrimaryKey integer (number(*,0) sur P_PATIENTS.IDPATIENT
    index varchar2(32 char) sur P_PATIENTS.Nom

    Requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT p.Nom, e.DATEEXAMEN
    FROM E_EXAMENS e
    INNER JOIN P_PATIENTS p on p.idpatient = e.idpatient
    ORDER By e.DateExamen Asc
    Plan :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    "Optimizer"	"Cost"	"Cardinality"	"Bytes"	"Partition Start"	"Partition Stop"	"Partition Id"	"ACCESS PREDICATES"	"FILTER PREDICATES"
    "SELECT STATEMENT"	"ALL_ROWS"	"1123"	"26471"	"2673571"	""	""	""	""	""
    "SORT(ORDER BY)"	""	"1123"	"26471"	"2673571"	""	""	""	""	""
    "HASH JOIN"	""	"507"	"26471"	"2673571"	""	""	""	""P"."IDPATIENT"="E"."IDPATIENT""	""
    "TABLE ACCESS(FULL) MEDIREPORT.E_EXAMENS"	""	"249"	"26470"	"582340"	""	""	""	""	""
    "TABLE ACCESS(FULL) MEDIREPORT.P_PATIENTS"	""	"97"	"22341"	"1764939"	""	""	""	""	""
    Pourquoi le plan ne tient t'il point compte de mes index ?

    Merci bcp à tout ceux qui prendront le temps de se poser la question

    Souch

  2. #2
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 075
    Points
    19 075
    Par défaut
    tout simplement parce que tu sélectionnes toutes les lignes des 2 tables

    Si tu rajoutes une jointure qui limite le résultat, tu devrais utiliser un index

  3. #3
    Membre régulier Avatar de souch
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2003
    Messages : 145
    Points : 124
    Points
    124
    Par défaut
    Salut OraFrance,

    Merci pour ta réponse, en effet ca aide de limiter le nombre de retour, cependant mes requettes gardaient des plans foireux (tout en natural, pas ou peut d'index utilisés).
    Je viens de trouver la solution :
    passer le optimizer_mode en mode 'RULE' (http://www.adp-gmbh.ch/ora/tuning/optimizer.html), je n'ai pas encore assez potassé pour piger pourquoi ca marche mieux avec, mais le résultat est équivoque : toutes mes requetes sont a présent faites en passant exclusivement par les indexs

  4. #4
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 075
    Points
    19 075
    Par défaut
    si c'est le cas ça veut dire que tes stats ne sont pas à jour. Le mode RULE est à éviter SURTOUT en 10g

  5. #5
    Membre régulier Avatar de souch
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2003
    Messages : 145
    Points : 124
    Points
    124
    Par défaut
    ha ? Pourtant c'est diablement efficace ^^
    Question bête, comment mettre à jours mes stats ?
    cette méthode est elle la bonne ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    analyze table <table name> compute statistics;
    Edit : après avoir passé le compute statistics sur toute mes tables et être repassé en mode 'ALL_ROWS', mes plans sont toujours faux (quasiment tout en access full), si je repasse en CHOOSE ou RULE, c'est impec...

  6. #6
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 075
    Points
    19 075
    Par défaut
    un beau plan d'exécution n'est pas forcément synonyme de performance. RULE est obsoléte. Quelle tête elle a ta requête maintenant ? Combien de lignes tu récupères ?

    et ANALYZE aussi est obsoléte, tu dois utiliser DBMS_STATS.

  7. #7
    Membre régulier Avatar de souch
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2003
    Messages : 145
    Points : 124
    Points
    124
    Par défaut
    Merci pour ton aide

    ANALYZE aussi est obsoléte
    rhaa, décidément je n'utilise que des fonctions obsolètes moi ^^

    la 1er requête tournait bien après avoir ajouté quelques filtres limitant le nombre de retours, et renvoyais le même temps d'exec quelque soit le mode.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Select * FROM
     ( SELECT rownum RNUM, p.Nom, e.DATEEXAMEN 
        FROM E_EXAMENS e 
        INNER JOIN P_PATIENTS p ON p.idpatient = e.idpatient 
        AND UPPER(P.NOM) like Upper('%BE%')
        ORDER BY e.DateExamen ASC
     )
    Where (RNUM <= 20) and (RNUM >= 10)
    // Vitesse accéptable
    cepandant avec des requettes + importantes, mon probleme reste entier :

    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
    SELECT * FROM
     ( SELECT rownum RNUM,
      STO.*,CAT.(...), PAT.(...), SMAT.(...),EXAM.(...)
     
    FROM STOCK STO
    INNER JOIN CATALOGUE CAT ON CAT.LOCALID=STO.CAT_IID
    INNER JOIN MATERIEL SMAT ON SMAT.STO_ID=STO.STO_ID AND SMAT.USAGE>0
    INNER JOIN E_EXAMENS EXAM ON EXAM.IDEXAMEN = STO.ID_OUT
    INNER JOIN P_PATIENTS PAT ON PAT.IDPATIENT=EXAM.IDPATIENT
    INNER JOIN E_OPERATEURS OPS ON OPS.IDPATIENT=EXAM.IDPATIENT 
               AND OPS.IDEXAMEN = EXAM.IDEXAMEN AND OPS.IDPRINC=1
    INNER JOIN G_IDENTITES IDE ON IDE.ididentite = OPS.ididentite
     
    WHERE STO.TYPE_OUT='P' AND STO.DATE_OUT is not null AND STO.ATTVALIDE=0  
    )
    WHERE (RNUM <= 500)
    MODE RULE = entre 0.060 et 0.100 sec
    MODE ALL_ROWS = entre 1 et 1.5 sec

    la totalité des champs utilisés pour les jointures et dans la clause where sont des index (pk pour les jointures).

    Ce qui me chagrine, c'est que la même requete sur la même structure, indexs et données sous Firebird 1.5 ne me posent aucun problèmes et réponde bcp + vite qu'oracle moi qui croyais que migrer dessus allais tout speeder

  8. #8
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 075
    Points
    19 075
    Par défaut
    essaye :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT /*+ FIRST_ROWS */
      STO.*,CAT.(...), PAT.(...), SMAT.(...),EXAM.(...)
     FROM STOCK STO
    INNER JOIN CATALOGUE CAT ON CAT.LOCALID=STO.CAT_IID
    INNER JOIN MATERIEL SMAT ON SMAT.STO_ID=STO.STO_ID AND SMAT.USAGE>0
    INNER JOIN E_EXAMENS EXAM ON EXAM.IDEXAMEN = STO.ID_OUT
    INNER JOIN P_PATIENTS PAT ON PAT.IDPATIENT=EXAM.IDPATIENT
    INNER JOIN E_OPERATEURS OPS ON OPS.IDPATIENT=EXAM.IDPATIENT 
               AND OPS.IDEXAMEN = EXAM.IDEXAMEN AND OPS.IDPRINC=1
    INNER JOIN G_IDENTITES IDE ON IDE.ididentite = OPS.ididentite
     
    WHERE STO.TYPE_OUT='P' AND STO.DATE_OUT IS NOT NULL AND STO.ATTVALIDE=0
    AND ROWNUM <= 500
    que donne l'explain plan ?


    et en passant, l'application d'une fonction sur une colonne ne permet pas d'utiliser l'index. Ainsi dans la jointure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AND UPPER(P.NOM) LIKE Upper('%BE%')
    si il y a un index sur NOM, il ne sera pas utiliser. Il faut faire un index de fonction éventuellement, l'idéal étant de stocker les noms en majuscules pour éviter le UPPER

  9. #9
    Membre régulier Avatar de souch
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2003
    Messages : 145
    Points : 124
    Points
    124
    Par défaut
    l'application d'une fonction sur une colonne ne permet pas d'utiliser l'index
    merci bcps, cette info va mettre très utile !!

    Effectivement, en FIRST_ROWS ca passe très bien , cela veut-il dire que pour chaque requête je doit choisir entre le mode standart (ALL_ROWS) et celui ci, et modifier toutes mes requêtes (plusieurs centaines... ) en leur appliquant le bon mode ?

  10. #10
    Membre régulier Avatar de souch
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2003
    Messages : 145
    Points : 124
    Points
    124
    Par défaut
    PS : En stockant les noms en maj, je perd les accents ... (désolé multi post, j'ai fait citation au lieu d'edition)

  11. #11
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 075
    Points
    19 075
    Par défaut
    tu peux le modifier au niveau des paramètres de la base

    FIRST_ROWS permet d'indiquer à Oracle qu'il doit s'attacher à récupérer les 1° lignes plus rapidement alors que ALL_ROWS permet à l'optimiseur de récupérer toutes les lignes avant de faire le tri et renvoyer le résultat.

    Au moins, là tu restes dans les précos Oracle

  12. #12
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 075
    Points
    19 075
    Par défaut
    Citation Envoyé par souch
    PS : En stockant les noms en maj, je perd les accents ...
    alors tu peux remplacer l'index par un index de fonction

  13. #13
    Membre régulier Avatar de souch
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juin 2003
    Messages : 145
    Points : 124
    Points
    124
    Par défaut
    Oki,
    je configure donc ma base pour qu'elle soit en FIRST_ROWS par défaut, et je refait le tour de mes tables pour ajouter les indexs manquants et en transformer un certain nombre en indexs de fonction :-)

    Merci pour ton aide précieuse !

    Souch

  14. #14
    Expert éminent sénior
    Avatar de orafrance
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    15 967
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 15 967
    Points : 19 075
    Points
    19 075
    Par défaut
    attention quand même, trop d'index tue l'index

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 16/04/2010, 17h06
  2. Réponses: 13
    Dernier message: 15/06/2009, 14h55
  3. Réponses: 1
    Dernier message: 15/01/2008, 12h39
  4. Afficher les pseudos qui ne commencent pas par une lettre.
    Par asoka13 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 09/07/2007, 17h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo