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 :

"Optimiser" une requête


Sujet :

Langage SQL

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur Symfony2
    Inscrit en
    Novembre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Développeur Symfony2
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2008
    Messages : 48
    Points : 18
    Points
    18
    Par défaut "Optimiser" une requête
    Bonjour,

    J'ai un problème assez simple / basique, j'ai cette requête:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT [...] 
    FROM A,B 
    WHERE A.Z =B.Z AND T = 12 
    OR  A.Z =B.Z AND T = 2
    Je présume qu'il y a un moyen plus simple pour arriver au méme résultat, car une condition est commune: A.Z =B.Z

    Des idées ?
    Merci

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    bonjour,


    déjà la syntaxe des jointures est normalisée de cette manière depuis plus de 20 ans :
    http://sqlpro.developpez.com/cours/s...ointures/#LIII


    Ensuite, pour quoi mettre 2 fois vos conditions de jointure ? utilisez des parenthèses ou un "IN"


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    select *
    from table_a a
    inner join table_b b on a.z = b.z
    where t in (2, 12)

  3. #3
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 109
    Points : 28 437
    Points
    28 437
    Par défaut
    Première étape : factoriser les conditions
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT  [...] 
    FROM    A,B 
    WHERE   A.Z = B.Z 
        AND (T = 12 OR  T = 2)
    ;
    C'est de l'algèbre de Boole, tout simplement.

    Seconde étape : utiliser un opérateur mieux adapté.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT  [...] 
    FROM    A,B 
    WHERE   A.Z = B.Z 
        AND T IN (12, 2)
    ;
    Troisième étape : écrire les jointures sous leur forme normalisée depuis deux décennies.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT  [...] 
    FROM    A
        INNER JOIN
            B 
            ON  A.Z = B.Z 
    WHERE   T IN (12, 2)
    ;
    Et c'est tout de suite beaucoup plus lisible

  4. #4
    Membre à l'essai
    Homme Profil pro
    Développeur Symfony2
    Inscrit en
    Novembre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Développeur Symfony2
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2008
    Messages : 48
    Points : 18
    Points
    18
    Par défaut
    Ensuite, pour quoi mettre 2 fois vos conditions de jointure ? utilisez des parenthèses ou un "IN"
    C'était justement ma question c'était tout bête, mais ça ne me venait pas...

    Pour la petite histoire, en DUT on m'a apprit le JOIN ON
    Que j'utilisais donc..

    Puis à la fac, on m'a dit que c'était la méme chose et que l'on pouvait utiliser les deux.. Donc selon mon humeur..
    Mais je ne savais pas que c'était normalisé depuis si longtemps, on aurait du nous le préciser qu'il y avait cette différence ^^
    Résolus donc, merci à vous

  5. #5
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 170
    Points : 7 422
    Points
    7 422
    Billets dans le blog
    1
    Par défaut
    Ton professeur de fac devrait être brûlé sur un bûcher.

    En effet, si au premier abords les deux syntaxes sont équivalentes :

    La jointure "from table1, table2 where ..." :
    1/ n'est pas une jointure, mais un produit cartésien
    2/ le filtre contient des critères de jointure qui n'ont rien d'un filtre
    1 + 2 => Sémantiquement, c'est donc complètement faux. L'optimiseur est donc pénalisé et doit réécrire complètement la requête pour pouvoir l'exécuter. Certains vieux SGBD en sont incapables.
    3/ N'est pas normalisée pour les jointures externes : selon le SGBD, on va avoir des "(+)" ajoutés derrière le nom des champs, ou un opérateur "*=".
    4/ Dans tous les cas, on ne peux pas faire de jointure externe en utilisant d'autres opérateurs que "=".
    5/ Les jointures en cascade sont pour ainsi dire impossible à écrire, et leur comportement n'est pas modulable sans se lancer dans des imbrications de sous-requêtes.
    6/ On ne peut faire que des jointures ouvertes droites ou gauches, pas de full
    3 + 4 + 5 + 6 => D'un point de vue lisibilité et fonctionnalités, les deux syntaxes ne sont donc absolument pas équivalentes.

    Bref : la normalisation SQL-92 est "obligatoire" si tu veux à la fois écrire un code propre, compréhensible, maintenable, optimisé et pouvoir profiter au mieux des possibilités de l'algèbre ensembliste pour interroger le SGBD.

  6. #6
    Membre à l'essai
    Homme Profil pro
    Développeur Symfony2
    Inscrit en
    Novembre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Développeur Symfony2
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2008
    Messages : 48
    Points : 18
    Points
    18
    Par défaut
    Merci pour cette réponse,

    En effet, je ne fais pas de requêtes très compliquées pour le moment, et je vais attendre ma note de bdd avant de proposer à mes camarades de brûler notre professeur

  7. #7
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 902
    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 902
    Points : 53 143
    Points
    53 143
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Ton professeur de fac devrait être brûlé sur un bûcher.
    ...
    Ben dis donc tu lui en as mis un couche !!!! Fais gaffe tu risque de devenir pire que moi !!!!

    A +

  8. #8
    Membre expert
    Homme Profil pro
    Retraité
    Inscrit en
    Octobre 2005
    Messages
    1 473
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Finance

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 473
    Points : 3 286
    Points
    3 286
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    ... En effet, si au premier abords les deux syntaxes sont équivalentes ...
    Ben si ... pour les jointures internes (INNER JOIN) c'est strictement identique ...

  9. #9
    Membre à l'essai
    Homme Profil pro
    Développeur Symfony2
    Inscrit en
    Novembre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Développeur Symfony2
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2008
    Messages : 48
    Points : 18
    Points
    18
    Par défaut
    Re Bonjour !

    J'ai donc cette requête là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT  [...] 
    FROM    A
        INNER JOIN
            B 
            ON  A.Z = B.Z 
    WHERE   T IN (12, 2)
    ;
    Dans ma table T est un historique et a une valeur de 0 à 15
    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ID - VAR
    1 - 2 
    2 - 2
    2 - 4
    Je ne veux sélectionner que les lignes qui ont 2 ou 12 dans leur historique mais je ne veux pas les sélectionner si d'autres lignes ont 4 dans leur historique par exemple, même si elles ont 2 ou 12 !
    Donc ici, je veux la ligne avec l'id 1 mais pas celle avec l'id 2 !

    Comment je pourrais faire ça ?

  10. #10
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    En d'autres mots, tu ne veux que les ID associés aux valeurs 2 et 12 mais pas ceux qui sont aussi associés à d'autres.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SELECT T1.ID
    FROM T T1
    WHERE T1.VAR IN(2, 15)
    	AND NOT EXISTS
    	(
    		SELECT *
    		FROM T T2
    		WHERE T2.ID = T1.ID
    			AND T2.VAR NOT IN (2,12)
    	)

  11. #11
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Tiens,

    Je n'ai pas encore résolu cette approche niveau perf, pour savoir qu'elle écriture est la mieux.


    Celle de Cinephil ou une du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT T1.ID
    FROM T T1
    group by T1.ID
    having sum(case when T1.VAR in (2, 12) then 0 else 1) = 0

  12. #12
    Membre à l'essai
    Homme Profil pro
    Développeur Symfony2
    Inscrit en
    Novembre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Développeur Symfony2
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2008
    Messages : 48
    Points : 18
    Points
    18
    Par défaut
    Bonjour,

    Merci pour les réponses, donc voici ma requéte:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT  distinct * FROM ps_orders 
    INNER JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order 
    WHERE  id_order_state IN ( 12 , 2) 
    AND NOT IN(
    		SELECT DISTINCT * FROM ps_orders 
    INNER JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order 
    WHERE  id_order_state IN ( 13) 
    	)
    Mais ça ne fonctionne pas.
    La premiére requéte me donne 3 commandes ( 4, 2 et 5001 )
    La deuxiéme me donne plusieurs fois la méme commande ( 5001 )

    Mais les deux combinées, ne me donne aucun résultat ( 0 )
    Des idées ?

    Merci !

  13. #13
    Membre chevronné
    Homme Profil pro
    Chef de projet MOA
    Inscrit en
    Février 2012
    Messages
    652
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet MOA
    Secteur : Distribution

    Informations forums :
    Inscription : Février 2012
    Messages : 652
    Points : 1 878
    Points
    1 878
    Par défaut
    Il y a une erreur dans votre code

    La syntaxe avec IN/NOT IN est plutôt comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT .. 
    FROM .. 
    WHERE champs1 IN 
      (SELECT champs10 
      FROM ..)
    Ce que tu as écrit ressemble d'avantage à un EXISTS/NOT EXISTS
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT ..
    FROM ..
    WHERE NOT EXISTS
      (SELECT ..
      FROM ..
      WHERE champs1 = champs10
    Après les résultat entre IN et EXISTS peuvent donner des résultats différents selon les valeurs NULL et il est souvent préférable d'utiliser l'opérateur EXISTS

  14. #14
    Membre à l'essai
    Homme Profil pro
    Développeur Symfony2
    Inscrit en
    Novembre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Développeur Symfony2
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2008
    Messages : 48
    Points : 18
    Points
    18
    Par défaut
    Ah mince, autant pour moi, la requéte originale que j'ai faites suivant la réponse précédente:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT  distinct * FROM ps_orders 
    INNER JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order 
    WHERE  id_order_state IN ( 12 , 2) 
    AND NOT EXISTS(
    		SELECT DISTINCT * FROM ps_orders 
    INNER JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order 
    WHERE  id_order_state IN ( 13) 
    	)
    Ce qui ne marche pas.

  15. #15
    Membre chevronné
    Homme Profil pro
    Chef de projet MOA
    Inscrit en
    Février 2012
    Messages
    652
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet MOA
    Secteur : Distribution

    Informations forums :
    Inscription : Février 2012
    Messages : 652
    Points : 1 878
    Points
    1 878
    Par défaut
    Il manque une jointure dans la sous-requête du NOT EXISTS

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT  DISTINCT * 
    FROM ps_orders O
      INNER JOIN ps_order_history 
        ON ps_orders.id_order = ps_order_history.id_order 
    WHERE  id_order_state IN ( 12 , 2) 
    AND NOT EXISTS
      (SELECT 1
      FROM ps_orders 
        INNER JOIN ps_order_history 
          ON ps_orders.id_order = ps_order_history.id_order 
      WHERE  id_order_state IN ( 13) 
      AND  O.id_order = ps_orders.id_orders
      )

  16. #16
    Membre à l'essai
    Homme Profil pro
    Développeur Symfony2
    Inscrit en
    Novembre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Développeur Symfony2
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2008
    Messages : 48
    Points : 18
    Points
    18
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT  DISTINCT * 
    FROM ps_orders O
      INNER JOIN ps_order_history 
        ON ps_orders.id_order = ps_order_history.id_order 
    WHERE  id_order_state IN ( 12 , 2) 
    AND NOT EXISTS
      (SELECT 1
      FROM ps_orders 
        INNER JOIN ps_order_history 
          ON ps_orders.id_order = ps_order_history.id_order 
      WHERE  id_order_state IN ( 13) 
      AND  O.id_order = ps_orders.id_orders
      )

    J'ai la méme erreur que lorsque j'essaye de donner un nom à mes tables:

    Unknown column 'ps_orders.id_order' in 'where clause'

  17. #17
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 109
    Points : 28 437
    Points
    28 437
    Par défaut
    Le message d'erreur est clair :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT  DISTINCT * 
    FROM ps_orders O
      INNER JOIN ps_order_history 
        ON ps_ordersO.id_order = ps_order_history.id_order 
    WHERE  id_order_state IN ( 12 , 2) 
    AND NOT EXISTS
      (SELECT 1
      FROM ps_orders 
        INNER JOIN ps_order_history 
          ON ps_orders.id_order = ps_order_history.id_order 
      WHERE  id_order_state IN ( 13) 
      AND  O.id_order = ps_orders.id_order
      )
    C'est une bonne habitude de donner un nom d'alias différent à chacune des tables utilisées dans une requête et de qualifier toutes les colonnes.

  18. #18
    Membre chevronné
    Homme Profil pro
    Chef de projet MOA
    Inscrit en
    Février 2012
    Messages
    652
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet MOA
    Secteur : Distribution

    Informations forums :
    Inscription : Février 2012
    Messages : 652
    Points : 1 878
    Points
    1 878
    Par défaut
    Sur quelle requête intervient l'erreur ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT  DISTINCT * 
    FROM ps_orders O1
      INNER JOIN ps_order_history H1
        ON O1.id_order = H1.id_order 
    WHERE  id_order_state IN (12 , 2) 
    AND NOT EXISTS
      (SELECT 1
      FROM ps_orders O2
        INNER JOIN ps_order_history H2
          ON O2.id_order = H2.id_order 
      WHERE  id_order_state IN (13) 
      AND  O1.id_order = O2.id_order
      )
    Je ne vois pas d'erreur dans le code précédent ...
    Sur quel SGBD travailles-tu ?

    EDIT : Bien joué Al1_24, j'avais justement réécrit la requête pour qu'elle soit plus claire à lire mais sans pour autant détecter l'erreur

  19. #19
    Membre à l'essai
    Homme Profil pro
    Développeur Symfony2
    Inscrit en
    Novembre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Développeur Symfony2
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2008
    Messages : 48
    Points : 18
    Points
    18
    Par défaut
    Ah oui, je pensais pas que ça changerais quelque chose, et qu'on pouvait utiliser O aussi bien que ps_orders..

    Merci du coup de main, j'aime pas vraiment les requêtes imbriquées..



    La requête finale:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SELECT  DISTINCT * 
    FROM ps_orders O
    INNER JOIN ps_order_history ON O.id_order = ps_order_history.id_order 
    WHERE  id_order_state IN ( 12 , 2) 
    AND NOT EXISTS(
    	SELECT DISTINCT * FROM ps_orders 
    	INNER JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order 
    	WHERE  id_order_state IN ( 13) 
    	AND  O.id_order = ps_orders.id_order
    	)

Discussions similaires

  1. Optimisation d'une requête patchwork
    Par ARRG dans le forum Langage SQL
    Réponses: 1
    Dernier message: 11/09/2005, 15h23
  2. optimisation d'une requête avec jointure
    Par champijulie dans le forum PostgreSQL
    Réponses: 8
    Dernier message: 07/07/2005, 09h45
  3. [DB2] Optimisation d'une requête
    Par ahoyeau dans le forum DB2
    Réponses: 7
    Dernier message: 11/03/2005, 17h54

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