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

Langage SQL Discussion :

Besoin d'aide pour optimiser requête SQL


Sujet :

Langage SQL

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 91
    Points : 92
    Points
    92
    Par défaut Besoin d'aide pour optimiser requête SQL
    Oracle 8i
    La table Histactu comporte environ 9 millions d'enregistrements
    Un exemple des données contenues dans la table histactu.
    CODAGT MOISPAIE CODRUB MONTANT CODETAT
    1 012005 10 1000 A
    1 012005 10 1050 N
    2 012005 10 2000 A
    3 012005 10 1500 A
    3 012005 10 1560 N
    Le but de la vue est de récupérer pour chaque enregistrement la ligne ou le CODETAT = N lorsque celui-ci existe et s'il n'existe pas prendre la ligne avec le CODETAT = A.
    D'après mon exemple le résultat attendu est le suivant :
    CODAGT MOISPAIE CODRUB MONTANT CODETAT
    1 012005 10 1050 N
    2 012005 10 2000 A
    3 012005 10 1560 N

    J'utilise le code ci-dessous pour crééer une vue

    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
     
    Create view view_histactu as
    select *
     from
      histactu hist1
    where
      hist1.ANMOIS > 200500 and
      codetat in (select max(hist2.codetat)
        from 
          histactu hist2
        where
          hist2.ANMOIS > 200500 and
          hist2.U##CODCOL = hist1.U##CODCOL and
          hist2.DATMAJ = hist1.DATMAJ and
          hist2.U##HHMMSS = hist1.U##HHMMSS and
          hist2.DTEDEB = hist1.DTEDEB and
          hist2.DTEFIN  = hist1.DTEFIN
        group by
          hist2.U##CODCOL, hist2.CODAGT, hist2.ANMOIS, 
          hist2.CODRUB,hisst2.DATMAJ, hist2.U##HHMMSS, hist2.DTEDEB, 
          hist2.DTEFIN)
    Lorsque je lance ensuite la requête suivante les temps de réponse sont très longs (environ 25mn)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    select 
      count(*)
    from 
      VIEW_HISTACTU
    where 
      codagt = 1
    Peut on optimiser la requête Sql qui est utilisée dans la création de la vue.
    Merci pour vos réponses.

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 862
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 862
    Points : 53 009
    Points
    53 009
    Billets dans le blog
    6
    Par défaut
    1) quel est le discrimant des lignes ? CODAGT + MOISPAIE + CODRUB ???
    2) d'ou viennent : U##CODCOL, U##HHMMSS, ANMOIS, DATEMAJ, DTEDEB , DTEFIN ???

    Sans ces données veut requête ne veut rien dire.

    SVP respectez ces règles : http://www.developpez.net/forums/viewtopic.php?t=32668

    A +

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 91
    Points : 92
    Points
    92
    Par défaut
    Dans mon exemple je n'ai pas cité l'ensemble des champs de la table histactu, les voici :
    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
     
     Nom                  Type
     ------------------ ----------------------------
     U##CODCOL   VARCHAR2(5)
     CODCOL          VARCHAR2(5)
     CODAGT          NUMBER
     U##CODORG   VARCHAR2(3)
     CODORG          VARCHAR2(3)
     CODRUB           NOT NULL NUMBER
     DTEDEB            DATE
     DTEFIN             DATE
     MONTANT          NUMBER
     TAUX                NUMBER
     BASE                NUMBER
     COEFF               NUMBER
     FLGORI              UMBER
     DTEREP             DATE
     MOISPAIE          NUMBER
     FLGCAL              NUMBER
     FLGVAL              NUMBER
     U##CODTRN      VARCHAR2(1)
     CODTRN             VARCHAR2(1)
     U##CODETAT     NOT NULL VARCHAR2(3)
     CODETAT            NOT NULL VARCHAR2(3)
     DATMAJ               DATE
     U##HHMMSS        VARCHAR2(30)
     HHMMSS               VARCHAR2(30)
     ANMOIS                NUMBER
    La clé est constituée de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    U##CODCOL 
    DATMAJ    
    U##HHMMSS
    DTEDEB 
    DTEFIN
    Merci pour vos réponses

  4. #4
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut
    Je ne suis pas certain d'avoir tout compris, mais essaye :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT * 
    FROM   histactu hist1 
    WHERE  hist1.ANMOIS > 200500 
      AND  codetat = (SELECT MAX(hist2.codetat) 
                       FROM   histactu hist2 
                       WHERE  hist2.ANMOIS    = hist1.ANMOIS 
                         AND  hist2.U##CODCOL = hist1.U##CODCOL 
                         AND  hist2.DATMAJ    = hist1.DATMAJ 
                         AND  hist2.U##HHMMSS = hist1.U##HHMMSS 
                         AND  hist2.DTEDEB    = hist1.DTEDEB 
                         AND  hist2.DTEFIN    = hist1.DTEFIN )

  5. #5
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 862
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 862
    Points : 53 009
    Points
    53 009
    Billets dans le blog
    6
    Par défaut
    Commencez par réformer votre clef. Elle comporte au max 41 octets => 10 mot du processeur. De plus elle est composite (plusieurs colonnes) et multitypé (char, date...) !!! De plus les colonnes la composant sont dispersées au lieu d'être regroupées de manière contigues. Pour couronner le tout vous utilisez systématiquement du varchar pour toutes vos colonnes, y compris celles situées entre les colonnes composant la clef... Cela induit des effets de lecture en "zigzag" si des mise à jour sont faites dans la table.

    Le tout impose vraisemblablement une vingtaine de passes dans le processeur pour chaque clef scrutée !

    Si votre clef était une unique colonne de type entier, vous gagneriez déjà énormément...

    A lire sur l'optimisation : http://sqlpro.developpez.com/cours/optimiser/

    A +

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 91
    Points : 92
    Points
    92
    Par défaut
    Citation Envoyé par Médiat
    Je ne suis pas certain d'avoir tout compris, mais essaye :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT * 
    FROM   histactu hist1 
    WHERE  hist1.ANMOIS > 200500 
      AND  codetat = (SELECT MAX(hist2.codetat) 
                       FROM   histactu hist2 
                       WHERE  hist2.ANMOIS    = hist1.ANMOIS 
                         AND  hist2.U##CODCOL = hist1.U##CODCOL 
                         AND  hist2.DATMAJ    = hist1.DATMAJ 
                         AND  hist2.U##HHMMSS = hist1.U##HHMMSS 
                         AND  hist2.DTEDEB    = hist1.DTEDEB 
                         AND  hist2.DTEFIN    = hist1.DTEFIN )
    Cette proposition ne renvoie que les enregistrements suivants voir exemple au début de mon post :
    1 012005 10 1050 N
    3 012005 10 1560 N
    Il manque l'enregistrement suivant :
    2 012005 10 2000 A

    Merci pour ta réponse.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 91
    Points : 92
    Points
    92
    Par défaut
    Citation Envoyé par SQLpro
    Commencez par réformer votre clef. Elle comporte au max 41 octets => 10 mot du processeur. De plus elle est composite (plusieurs colonnes) et multitypé (char, date...) !!! De plus les colonnes la composant sont dispersées au lieu d'être regroupées de manière contigues. Pour couronner le tout vous utilisez systématiquement du varchar pour toutes vos colonnes, y compris celles situées entre les colonnes composant la clef... Cela induit des effets de lecture en "zigzag" si des mise à jour sont faites dans la table.

    Le tout impose vraisemblablement une vingtaine de passes dans le processeur pour chaque clef scrutée !

    Si votre clef était une unique colonne de type entier, vous gagneriez déjà énormément...

    A lire sur l'optimisation : http://sqlpro.developpez.com/cours/optimiser/

    A +
    Je suis tout à fait d'accord sur le manque évident de performances que représente une table avec cette structure. Malheureusement je ne suis pas à l'origine de la conception et n'ai pas les moyens d'intervenir dessus.
    J'ai un peu progressé avec le code suivant :
    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
     
    SELECT
    HA.CODCOL,                 
    HA.CODAGT,                
    HA.CODORG,               
    HA.CODRUB,              
    HA.DTEDEB,             
    HA.DTEFIN,            
    decode(upper(HN.CODETAT),'N',HN.MONTANT,HA.MONTANT) montant,
    decode(upper(HN.CODETAT),'N',HN.TAUX   ,HA.TAUX )   taux,
    decode(upper(HN.CODETAT),'N',HN.BASE   ,HA.BASE )   base,
    HA.COEFF  ,        
    HA.FLGORI ,       
    HA.DTEREP ,      
    HA.MOISPAIE,     
    HA.FLGCAL  ,    
    HA.FLGVAL  ,   
    HA.CODTRN  ,  
    decode(upper(HN.CODETAT),'N',HN.CODETAT,HA.CODETAT) codetat , 
    HA.DATMAJ  ,
    HA.HHMMSS  ,
    HA.ANMOIS
    FROM
      pers.HistActu HA,
      pers.HistActu HN
    WHERE HN.CODAGT (+) = HA.CODAGT
        and HN.U##CODCOL (+) = HA.U##CODCOL
        and HN.DATMAJ (+) = HA.DATMAJ
        and HN.U##HHMMSS (+) = HA.U##HHMMSS
        and HN.CODRUB (+) = HA.CODRUB
        and HN.anmois (+) = HA.anmois
        and HN.FLGVAL (+) = HA.FLGVAL
        and ( upper(HA.codetat) = 'A')
    AND ( nvl(HN.FLGVAL,1) = 1 )
    and ( HN.codetat (+) <> 'a' AND HN.codetat (+) <> 'A')
    Mais cette solution bien que plus performante ne renvoie pas tous les enregistrements voulus :
    La requête retourne :
    Les enregistrements avec codetat = "A" si il n'existe pas de codetat = "N"
    Les enregistrements avec codetat = "N" si il existe un codetat = "A"

    Il manque :
    Les enregistrements avec codetat = "N" si il n'existe pas de codetat = "A"
    Merci pour vos réponses.

  8. #8
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut
    Comme je ne maîtrise pas toutes tes données, j'ai recopié ta liste, mais si je juge par tes exemples :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT * 
    FROM   histactu hist1 
    WHERE  hist1.ANMOIS > 200500 
      AND  codetat = (SELECT MAX(hist2.codetat) 
                       FROM   histactu hist2 
                       WHERE  hist2.ANMOIS    = hist1.ANMOIS 
                         AND  Les liens nécessaires entre hist1 et hist2, c'est à dire tout ce qu'il y a de commun entre la ligne avec A et la ligne avec B (il n'y a sans doute ni la date ni l'heure, mais je ne peux pas savoir...)

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 91
    Points : 92
    Points
    92
    Par défaut
    Citation Envoyé par Médiat
    Comme je ne maîtrise pas toutes tes données, j'ai recopié ta liste, mais si je juge par tes exemples :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT * 
    FROM   histactu hist1 
    WHERE  hist1.ANMOIS > 200500 
      AND  codetat = (SELECT MAX(hist2.codetat) 
                       FROM   histactu hist2 
                       WHERE  hist2.ANMOIS    = hist1.ANMOIS 
                         AND  Les liens nécessaires entre hist1 et hist2, c'est à dire tout ce qu'il y a de commun entre la ligne avec A et la ligne avec B (il n'y a sans doute ni la date ni l'heure, mais je ne peux pas savoir...)
    Je pense que le problème n'est pas dans les liens, c'est simplement qu'il n'existe pas de "group by" dans la sous requête, à partir de ce moment le MAX(CODETAT) est égal à "N" systématiquement mais sinon effectivement la clause "=" est plus performante que mon "in" mais cela reste malgré tout trop long.
    Merci pour ta réponse.

  10. #10
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut
    Citation Envoyé par Keuf95
    Je pense que le problème n'est pas dans les liens, c'est simplement qu'il n'existe pas de "group by" dans la sous requête, à partir de ce moment le MAX(CODETAT) est égal à "N" systématiquement
    Pas besoin de GROUP BY, le WHERE doit faire tout le boulot, si je m'en tiens à ton exemple du début, je mettrais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WHERE hist2.MOISPAIE    = hist1.MOISPAIE
      AND hist2.CODRUB    = hist1.CODRUB

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 91
    Points : 92
    Points
    92
    Par défaut
    Merci, Médiat c'est tout de même plus rapide que ma requête de départ et ça marche . De toutes façons je ne pense pas que je puisse obtenir beaucoup mieux vu la structure de la table.
    Pour te donner plus de détails je me connecte ensuite sur cette vue Oracle à l'aide d'ACCESS en ODBC et les temps de réponse étaient tellement long que cela générait une erreur au niveau de la connexion ODBC, maintenant ça fonctionne.
    A+

Discussions similaires

  1. Besoin d'aide pour une requête SQL
    Par p_oum dans le forum MS SQL Server
    Réponses: 9
    Dernier message: 26/11/2009, 09h29
  2. Besoin d'aide pour une requête SQL
    Par sexy-meta dans le forum Langage SQL
    Réponses: 6
    Dernier message: 08/07/2008, 14h36
  3. Besoin d'aide pour une requête SQL
    Par FranckyVegas dans le forum Langage SQL
    Réponses: 7
    Dernier message: 27/05/2008, 20h16
  4. Besoin d'aide pour une requête SQL
    Par Borami dans le forum Langage SQL
    Réponses: 1
    Dernier message: 07/11/2005, 10h33
  5. Besoin d'aide pour une Requête SQL ...
    Par Kokito dans le forum Requêtes
    Réponses: 2
    Dernier message: 07/07/2004, 11h56

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