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

SQL Oracle Discussion :

[Débutant] Optimisation de requête ?


Sujet :

SQL Oracle

  1. #1
    Membre averti
    Homme Profil pro
    Consultant en Business Intelligence
    Inscrit en
    Mai 2003
    Messages
    921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Consultant en Business Intelligence

    Informations forums :
    Inscription : Mai 2003
    Messages : 921
    Points : 449
    Points
    449
    Par défaut [Débutant] Optimisation de requête ?
    Bonjour à tous,

    j'ai une table contenant des évènements lesquels ayant une date de fermeture.

    Il me faut récupérer tous les évènements dont la date de fermeture arrive à échéance la semaine précédent la semaine du jour d'exécution de la requête.

    Ceux qui ont compris peuvent lever la main ... les autres relisez ma phrase, car j'ai fait un effort !

    Extrait de la requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    AND (-- condition "normale"
        TO_CHAR(CAL.CAL_DAT_FER, 'YYYY') = TO_CHAR(SYSDATE, 'YYYY')
        AND TO_CHAR(CAL.CAL_DAT_FER, 'WW') = (TO_CHAR(SYSDATE, 'WW') - 1)
    )
    OR (-- oui ... 1ère semaine de l'année - 1 = dernière semaine de l'année précédente (= 52) !
        TO_CHAR(CAL.CAL_DAT_FER, 'YYYY') = (TO_CHAR(SYSDATE, 'YYYY') - 1)
        AND TO_CHAR(CAL.CAL_DAT_FER, 'WW') = '52'
        AND TO_CHAR(SYSDATE, 'WW') = '01'
    )

    Alors qui saura optimiser ma condition ?!

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    354
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 354
    Points : 436
    Points
    436
    Par défaut
    Que pensez-vous de ça?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    (
        CAL.CAL_DAT_FER >= next_day ( trunc(sysdate) - 14, 1)
    AND
        CAL.CAL_DAT_FER < next_day ( trunc(sysdate) - 7, 1)
    )

  3. #3
    Rédacteur
    Avatar de Bruno2r
    Homme Profil pro
    Exploitation des données
    Inscrit en
    Décembre 2006
    Messages
    2 566
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Exploitation des données
    Secteur : Santé

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 566
    Points : 4 780
    Points
    4 780
    Par défaut
    Et de ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AND (sysdate - CAL.CAL_DAT_FER) < 14

  4. #4
    Membre averti
    Homme Profil pro
    Consultant en Business Intelligence
    Inscrit en
    Mai 2003
    Messages
    921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Consultant en Business Intelligence

    Informations forums :
    Inscription : Mai 2003
    Messages : 921
    Points : 449
    Points
    449
    Par défaut
    Citation Envoyé par Bruno2r Voir le message
    Et de ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AND (sysdate - CAL.CAL_DAT_FER) < 14
    Je ne pense pas que cette solution soit viable, puisqu'il faut uniquement que la date de fermeture soit comprise dans la semaine précédent la date d'exécution et non pas le jour précédent par exemple. Ce qui serait le cas lorsque ta condition renverra 1, non ?

  5. #5
    Membre régulier
    Homme Profil pro
    Inscrit en
    Mai 2007
    Messages
    187
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 187
    Points : 110
    Points
    110
    Par défaut
    Une autre solution est de créer des index.

    Attention l'index doit etre crée sur la fonction
    TO_CHAR(CAL.CAL_DAT_FER, 'YYYY')

    et pas simplement sur la colonne CAL.CAL_DAT_FER

    sinon le SGBD (sur Oracle en tous cas) n'est pas capable d'utiliser l'index.

    P.

  6. #6
    Membre averti
    Homme Profil pro
    Consultant en Business Intelligence
    Inscrit en
    Mai 2003
    Messages
    921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Consultant en Business Intelligence

    Informations forums :
    Inscription : Mai 2003
    Messages : 921
    Points : 449
    Points
    449
    Par défaut
    Citation Envoyé par Michel SALAIS Voir le message
    Que pensez-vous de ça?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    (
        CAL.CAL_DAT_FER >= next_day ( trunc(sysdate) - 14, 1)
    AND
        CAL.CAL_DAT_FER < next_day ( trunc(sysdate) - 7, 1)
    )
    Cette solution fonctionne effectivement, mais est moins optimale que ma méthode.

    Ta méthode : 280 746 (coût) et 10,5 secondes (en moyenne) pour 31 888 résultats.

    Ma méthode : 14 918 (coût) et 8,2 secondes (en moyenne) pour 31 888 résultats.

  7. #7
    Membre averti
    Homme Profil pro
    Consultant en Business Intelligence
    Inscrit en
    Mai 2003
    Messages
    921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Consultant en Business Intelligence

    Informations forums :
    Inscription : Mai 2003
    Messages : 921
    Points : 449
    Points
    449
    Par défaut
    Citation Envoyé par pdelorme Voir le message
    Une autre solution est de créer des index.
    J'ai beaucoup d'autres conditions dans ma requête et quasiment toutes sur une et unique table. J'ai donc créé un index sur les champs les plus discriminants. La table étant très lourde je suis passé d'un cout de 1.8 * 10^18 à 14 918 !!!

    Citation Envoyé par pdelorme Voir le message
    Attention l'index doit etre crée sur la fonction
    TO_CHAR(CAL.CAL_DAT_FER, 'YYYY')

    et pas simplement sur la colonne CAL.CAL_DAT_FER

    sinon le SGBD (sur Oracle en tous cas) n'est pas capable d'utiliser l'index.

    P.
    Penses-tu qu'il est vraiment utile de créer cet index supplémentaire et si oui comment ?!

    Je n'ai jamais créé d'index intégrant une fonction, uniquement sur des champs.

    De plus, j'utilise Oracle SQL Developer et je crée mes index en mode graphique habituellement et non pas en ligne de commande.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    354
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 354
    Points : 436
    Points
    436
    Par défaut
    Citation Envoyé par ghohm Voir le message
    Cette solution fonctionne effectivement, mais est moins optimale que ma méthode.

    Ta méthode : 280 746 (coût) et 10,5 secondes (en moyenne) pour 31 888 résultats.

    Ma méthode : 14 918 (coût) et 8,2 secondes (en moyenne) pour 31 888 résultats.
    Et si un index est créé sur la colonne ...

    Le coût constaté ici par l'optimiseur peut être discutable !

  9. #9
    Membre averti
    Homme Profil pro
    Consultant en Business Intelligence
    Inscrit en
    Mai 2003
    Messages
    921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Consultant en Business Intelligence

    Informations forums :
    Inscription : Mai 2003
    Messages : 921
    Points : 449
    Points
    449
    Par défaut
    Comme disait pdelorme :

    Citation Envoyé par pdelorme Voir le message
    Une autre solution est de créer des index.

    Attention l'index doit etre crée sur la fonction
    TO_CHAR(CAL.CAL_DAT_FER, 'YYYY')

    et pas simplement sur la colonne CAL.CAL_DAT_FER

    sinon le SGBD (sur Oracle en tous cas) n'est pas capable d'utiliser l'index.

    P.
    Par contre je ne sais pas comment créer un index sur une colonne à laquelle est appliquée une fonction !?

  10. #10
    Rédacteur
    Avatar de Bruno2r
    Homme Profil pro
    Exploitation des données
    Inscrit en
    Décembre 2006
    Messages
    2 566
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Exploitation des données
    Secteur : Santé

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 566
    Points : 4 780
    Points
    4 780
    Par défaut
    Citation Envoyé par ghohm Voir le message
    Je ne pense pas que cette solution soit viable, puisqu'il faut uniquement que la date de fermeture soit comprise dans la semaine précédent la date d'exécution et non pas le jour précédent par exemple. Ce qui serait le cas lorsque ta condition renverra 1, non ?
    Exact j'ai voulu aller trop vite ... désolé
    Il suffit d'ajouter le test sur la semaine :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    AND (
    (sysdate - CAL.CAL_DAT_FER) < 14 
    AND TO_CHAR(CAL.CAL_DAT_FER, 'WW') != TO_CHAR(SYSDATE, 'WW')
    )

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    354
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 354
    Points : 436
    Points
    436
    Par défaut
    Citation Envoyé par ghohm Voir le message
    Comme disait pdelorme :

    Par contre je ne sais pas comment créer un index sur une colonne à laquelle est appliquée une fonction !?
    Justement la solution que je te propose ne nécessite pas d'index basé sur une fonction

    Juste un index normal ...

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    354
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 354
    Points : 436
    Points
    436
    Par défaut
    Citation Envoyé par ghohm Voir le message
    Cette solution fonctionne effectivement, mais est moins optimale que ma méthode.

    Ta méthode : 280 746 (coût) et 10,5 secondes (en moyenne) pour 31 888 résultats.

    Ma méthode : 14 918 (coût) et 8,2 secondes (en moyenne) pour 31 888 résultats.
    En fait c'est les curiosités de sysdate et le plan d'exécution que j'ai testé ajoute un filtre lorsqu'il s'agit de sysdate!

    En fin voici un test pour comparer les deux méthodes sans les "conneries" de sysdate en ce qui concerne ma solution

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    set echo on
    set timing on
    
    drop table test purge;
    create table test (a date);
    
    insert into test
    select rownum / (24 * 60) + sysdate - 1000
    from dba_objects, dba_objects
    where rownum <= 10000000;
    
    select count(*)
    from test
    where (-- condition "normale"
        TO_CHAR(a, 'YYYY') = TO_CHAR(SYSDATE, 'YYYY')
        AND TO_CHAR(a, 'WW') = (TO_CHAR(SYSDATE, 'WW') - 1)
    )
    OR (-- oui ... 1ère semaine de l'année - 1 = dernière semaine de l'année précédente (= 52) !
        TO_CHAR(a, 'YYYY') = (TO_CHAR(SYSDATE, 'YYYY') - 1)
        AND TO_CHAR(a, 'WW') = '52'
        AND TO_CHAR(SYSDATE, 'WW') = '01'
    )
    
    COUNT(*)               
    ---------------------- 
    10080                  
    
    1 rows selected
    
    16,722ms elapsed
    declare
      fin date;
      debut date;
      cnt number;
    begin
      fin := next_day (trunc(sysdate) - 7, 'lundi');
      debut := next_day (trunc(sysdate) - 14, 'lundi');
      select count(*)
      into cnt
      from test
      where a >= debut
        and a < fin;
    end;
    
    anonymous block completed
    695ms elapsed

Discussions similaires

  1. [Débutant] optimiser une requète
    Par tatayet_le_felee dans le forum SQL
    Réponses: 7
    Dernier message: 27/01/2009, 21h35
  2. Débutant: optimisation de requête
    Par knotpio dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 09/02/2008, 17h01
  3. optimisation des requêtes
    Par yech dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 21/09/2004, 19h03
  4. [débutant] Problème de requête
    Par gandalf_le_blanc dans le forum Langage SQL
    Réponses: 6
    Dernier message: 25/06/2004, 13h32
  5. Optimisation de requête
    Par olivierN dans le forum SQL
    Réponses: 10
    Dernier message: 16/12/2003, 10h09

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