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

Requêtes MySQL Discussion :

Comment optimiser une requête SELECT sur une multitude de tables ?


Sujet :

Requêtes MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 18
    Par défaut Comment optimiser une requête SELECT sur une multitude de tables ?
    Bonjour à tous !

    Voilà j'ai une base de données sous la forme:
    OBJET(idObj, nomObj, descObj, ...)
    CARAC(idCarac, #idObj, nomCarac, descCarac, valeurCarac, ...)
    INGREDIENT(idIng, #idObj, nomIng, descIng, quantiteIng, ...)

    Un objet peut avoir 0 ou N caracs
    Un objet peut avoir 1 ou X ingrédients

    Si je veux récupérer le détail d'un objet, disons l'objet numéro 67, je fais une 1ère requête pour récupérer les informations de la table Objet (qui fonctionne un peu comme une table header):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT idObj, nomObj, descObj, ... FROM OBJET WHERE idObj = 67;
    Ensuite je fais une 2ème requête pour récupérer les informations de la table Carac (qui fonctionne un peu comme une table items):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT idCarac, nomCarac, descCarac, valeurCarac FROM CARAC where idObj = 67;
    Ensuite je fais une 3ème requête pour récupérer les informations de la table Ingredient (qui fonctionne aussi un peu comme une table items):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT idIng, nomIng, descIng, quantiteIng FROM INGREDIENT where idObj = 67;
    Cela me fait donc 3 requêtes SQL pour récupérer les informations d'un objet.
    Maintenant disons que j'ai besoin de récupérer un ensemble d'objets.
    J'effectue les requêtes suivantes:

    1ère requête pour récupérer les informations de la table Objet (qui fonctionne un peu comme une table header):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT idObj, nomObj, descObj, ... FROM OBJET WHERE idObj IN (67, 68, 69, 70);
    Ensuite je fais une 2ème requête pour récupérer les informations de la table Carac (qui fonctionne un peu comme une table items):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT idCarac, idObj, nomCarac, descCarac, valeurCarac FROM CARAC where idObj IN (67, 68, 69, 70);
    Ensuite je fais une 3ème requête pour récupérer les informations de la table Ingredient (qui fonctionne aussi un peu comme une table items):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT idIng, idObj, nomIng, descIng, quantiteIng FROM INGREDIENT where idObj IN (67, 68, 69, 70);
    J'ai déjà pensé à créer une vue avec jointures mais je vois pas trop comment la faire car si je récupère dans la même vue les informations de OBJET, CARAC et INGREDIENT, je vais me retrouver avec les champs de OBJET répétés N fois (N Caracs) ou X fois (X Ingrédients) et puis ça paraît bien bancale car on aura max(N, X) lignes.

    - Y a t-il un meilleur moyen de récupérer les informations d'un objet ou d'un ensemble d'objets que mes 3 requêtes citées plus haut ?
    - Serait-il judicieux de passer par des vues formées de jointures, si oui lesquelles ?

    Maintenant pour compliquer un peu les choses, j'ai besoin de faire des SELECT sur plusieurs critères d'objets. Par exemple, il arrive d'avoir besoin de trouver l'objet dont:
    - nomObj LIKE 'foo%'
    - ( (nomCarac = A ET valeurCarac > 5) ET (nomCarac = B ET valeurCarac > 10) ) OU ( (nomCarac = C ET valeurCarac > 10) ET (nomCarac = D ET valeurCarac > 20) )

    La seule façon que j'ai trouvé pour rechercher un tel objet dans mes tables c'est:
    Faire une 1ère requête sur la table OBJET:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT idObj FROM OBJET WHERE nomObj LIKE 'foo%';
    Puis faire une 2ème requête sur la table CARAC:
    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
    SELECT idObj FROM CARAC
    WHERE idObj IN ("resultat Requête 1")
    AND
    (
      (nomCarac = A AND valeurCarac > 5)
      OR
      (nomCarac = B AND valeurCarac > 10)
    )
    GROUP BY idObj
    HAVING count(idObj) = 2
    UNION
    SELECT  idObj FROM CARAC
    WHERE idObj IN ("resultat Requête 1")
    AND (
      (nomCarac = C AND valeurCarac > 10)
      OR
      (nomCarac = D AND valeurCarac > 20)
    )
    GROUP BY idObj
    HAVING count(num) = 2
    Cela me donne donc tous les IdObj qui remplissent les critères définis par l'utilisateur, et ensuite je peux faire mes 3 requêtes énoncées au début du message pour récupérer l'ensemble des informations de chaque objet.

    Seulement je trouve cette méthode très lourde. Beaucoup de requêtes pour arriver à mes fins, et je ne parle pas du casse-tête pour générer dynamiquement ce genre de requêtes dans un langage comme PHP.

    - Voyez-vous une façon plus simple et plus optimisée peut être de faire tout ça ?

    Merci énormément pour ceux qui auront pris le temps de me lire et de me donner leurs conseils

    Cordialement.

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

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

    Au vu de la modélisation, votre approche est bonne.

    Et vous n'avez pas moyen de la simplifier.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 18
    Par défaut
    Merci pour votre réponse punkoff.
    Dans ce cas pensez-vous que la modélisation puisse être améliorée ?

    Serait-il judicieux par exemple de créer une vue dédiée à la recherche qui regroupe tous les champs utilisés dans les critères de recherche via un LEFT JOIN:
    VUE RECHERCHE(idObj, idCarac, nomObj, nomCarac, valeurCarac)

    Cela crée une redondance des champs de la table OBJET (nomObj par ex) mais cela permet d'éviter l'utilisation de 2 requêtes avec un idObj IN (x,y,z) dans la seconde requête. Seulement je ne sais pas si cela est préférable.

    Merci, cordialement.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Février 2005
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 18
    Par défaut
    J'ai trouvé une meilleure façon d'effectuer la requête de recherche dans mes tables.

    Au lieu de la requête suivante qui est assez gourmande je pense car elle utilise GROUP BY + HAVING + COUNT:

    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
    SELECT idObj FROM CARAC
    WHERE idObj IN ("resultat Requête 1")
    AND
    (
      (nomCarac = A AND valeurCarac > 5)
      OR
      (nomCarac = B AND valeurCarac > 10)
    )
    GROUP BY idObj
    HAVING count(idObj) = 2
    UNION
    SELECT  idObj FROM CARAC
    WHERE idObj IN ("resultat Requête 1")
    AND (
      (nomCarac = C AND valeurCarac > 10)
      OR
      (nomCarac = D AND valeurCarac > 20)
    )
    GROUP BY idObj
    HAVING count(num) = 2
    J'ai opté pour cette requête qui n'utilise que des jointures, opération la plus courante et optimisée dans un SGBDR digne de ce nom

    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
    SELECT C.idObj
    FROM CARAC C
    INNER JOIN CARAC C1 ON C.idObj = C1.idObj
    INNER JOIN CARAC C2 ON C.idObj = C2.idObj
    WHERE C.idObj IN ("resultat Requête 1")
    AND (C1.nomCarac = A AND C1.valeurCarac > 5)
    AND (C2.nomCarac = B AND C2.valeurCarac > 10)
    UNION
    SELECT C.idObj
    FROM CARAC C
    INNER JOIN CARAC C1 ON C.idObj = C1.idObj
    INNER JOIN CARAC C2 ON C.idObj = C2.idObj
    WHERE C.idObj IN ("resultat Requête 1")
    AND (C1.nomCarac = C AND C1.valeurCarac > 10)
    AND (C2.nomCarac = D AND C2.valeurCarac > 20)
    Qu'en pensez-vous ?

Discussions similaires

  1. [PDO] SELECT dans une requète SQL sur une page PHP
    Par thewit dans le forum PHP & Base de données
    Réponses: 7
    Dernier message: 19/01/2015, 22h48
  2. Pb sur une requête DELETE sur une chaine
    Par astrolane dans le forum Sybase
    Réponses: 4
    Dernier message: 16/02/2009, 09h11
  3. [MySQL] Erreur sur une requête select where
    Par Goffer dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 04/01/2009, 08h45
  4. Réponses: 0
    Dernier message: 06/08/2008, 11h44
  5. Optimisation d'une requête SELECT sur une grosse table
    Par eracius dans le forum Requêtes
    Réponses: 4
    Dernier message: 26/05/2008, 14h51

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