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 :

Optimisation requête sql avec jointures n,n


Sujet :

Requêtes MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut Optimisation requête sql avec jointures n,n
    Bonjour et merci pour votre aide.
    Voici un exemple BIDON de base de données pour présenter ma question

    Voir schéma en pièce jointe

    - 1 voiture peut avoir plusieurs couleurs, 1 couleur peut appartenir à plusieurs voitures (n,n)
    - 1 voiture peut avoir plusieurs passagers, 1 passager peut appartenir à plusieurs voitures (n,n)
    - 1 voiture appartient à 1 concessionnaire, 1 concessionnaire peut avoir plusieurs voitures.

    Je voudrais afficher le résultat comme un catalogue, c'est à dire :
    une liste de 20 voitures par page avec pour chacune toutes ses couleurs et tous ses passagers...

    1) Je fais une première requête pour récupérer les voitures par concessionnaire, ensuite dans une boucle while je récupère pour chaque voitures les couleurs etc... Mauvaise solution je pense car trop de requêtes. (21)

    2) on utilise les jointures. Avec 1 couleur et 1 passager c'est easy. Mais dans ce cas, il faut que je récupère toutes les couleurs et tous les passagers. Je vais donc récupérer une liste avec plusieurs lignes pour la même voiture selon le nombre de couleurs et le nombre de passagers qu'il y a. Et donc je vois mal comment traiter ce genre de liste en php ?

    J'espère que vous avez compris m'a problématique (Il y a peut être un chapitre dans sql ou dans php qui m'échappe...) j'aimerais utiliser le moins de requêtes possibles.

    Merci pour votre aide
    Images attachées Images attachées  
    Dernière modification par Invité ; 09/11/2012 à 20h17.

  2. #2
    Membre Expert
    Avatar de ericd69
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    1 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

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

    Informations forums :
    Inscription : Avril 2011
    Messages : 1 919
    Billets dans le blog
    1
    Par défaut
    salut,

    là faut clairement que tu fasses des jointures...
    lister toutes les voitures d'un concessionnaire:
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    select v.nom as `vehicule`,v.marque as `marque`, c.couleur as `couleur`,
      p.passagers_avant as `avant`,p.passagers_arriere as `arriere`
    from voitures v
    inner join concessionnaire c on c.id_concessionnaire=v.concessionnaire_id
      and c.nom='truc'# là tu remplaces par le le nom du concessionnaire voulu
    left join voitures_has_couleurs vhc on vhc.id_voitures=v.id_voitures
      left join couleurs c on vhc.id_couleurs=c.id_couleurs
    left join voitures_has_passagers vhp on vhp.id_voitures=v.id_voitures
      left join passagers p on vhp.id_passagers=p.id_passagers
    de tête, ça devrait te sortir le bon truc...

    à toi de te débrouiller pour adapter ça à ton problème si tu as d'autres requêtes à faire... mais tu vois c'est pas si dur... faut penser ensembles de données et sélection dans ceux-ci...

    par contre:
    • évite de mélanger français et anglais, singulier et pluriels...
    • essaye d'avoir une logique de nommage que tu appliques pour les noms de colonnes genre id,nom,... pour les colonnes normales et clé primaire et id_machin,id_truc pour les clés étrangères... ça simplifie les noms et l'écriture tu crois pas?
    • enfin dimensionne tes colonnes indexées au plus juste: y a pas plus de 255 couleurs possibles donc tinyint unsigned suffira par exemple et les combinaisons pour les passagers pareil je pense... ou smallint unsigned (un peu plus de 16000 possibilités ) suffira au pire... plus tes index sont compacts, plus ils tiennent dans le buffer d'index et moins tu lis vraiment tes tables pour les jointures... unsigned permet de ne pas perdre les valeurs négatives dans les espaces de valeurs possibles...


    je te conseille d'encapsuler tes requêtes dans des procédures stockées pour éviter de les renvoyer à chaque fois...
    genre pour la même requête:
    Code sql : 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
    delimiter $$
    drop procedure if exists voitures_chez_concessionnaire$$
    create procedure voitures_chez_concessionnaire(in n varchar(45))
    begin
      select v.nom as `vehicule`,v.marque as `marque`, c.couleur as `couleur`,
        p.passagers_avant as `avant`,p.passagers_arriere as `arriere`
      from voitures v
      inner join concessionnaire c on c.id_concessionnaire=v.concessionnaire_id
        and c.nom=n
      left join voitures_has_couleurs vhc on vhc.id_voitures=v.id_voitures
        left join couleurs c on vhc.id_couleurs=c.id_couleurs
      left join voitures_has_passagers vhp on vhp.id_voitures=v.id_voitures
        left join passagers p on vhp.id_passagers=p.id_passagers;
    end$$
    delimiter ;
     
    #appel
    call voitures_chez_concessionnaire('truc');

  3. #3
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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 818
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par ericd69 Voir le message
    par contre:[*]évite de mélanger français et anglais, singulier et pluriels...
    Oui.
    D'une manière générale, on nomme les entités types d'un MCD avec des noms au singulier et les associations avec un verbe à l'infinitif. Ces noms conduisent à faire la même chose quand on passe aux tables.
    Idem bien sûr pour les colonnes : le singulier est de mise afin de ne pas introduire l'ambiguïté de savoir si la colonne est multivaluée ou pas.

    [*]essaye d'avoir une logique de nommage que tu appliques pour les noms de colonnes genre id,nom,... pour les colonne normales et clé primaire et id_machin,id_truc pour les clés étrangères... ça simplifie les noms et l'écriture tu crois pas?
    Oui et non.
    Avec un tel système trop simple, on arrive un jour à nommer une colonne "date" ou "action" ou "domain" ou "element"... qui sont des mots réservés du SQL.
    Il faut s'imposer un standard de nommage un peu plus élaboré qui clarifie les requêtes en indiquant de quelle table provient telle colonne et en empêchant naturellement un mot interdit. On peut s'inspirer de celui de SQLPro qui semble rébarbatif a priori mais qui devient vite naturel.

    [*]enfin dimensionne tes colonnes indexée au plus juste: y a pas plus de 255 couleurs possibles donc tinyint unsigned suffira par exemple et les combinaisons pour les passagers pareil je pense... ou smallint unsigned (un peu plus de 16000 possibilités ) suffira au pire...
    Oui et non.
    Pour ce cas des couleurs de voitures, qui cependant semble fictif, je pense que le nuancier général de toutes les voitures de tous les constructeurs doit être assez considérable pour justifier au moins un SMALLINT.

    plus tes index sont compact plus ils tiennent dans le buffer d'index et moins tu lis vraiment tes tables pour les jointures... unsigned permet de ne pas perdre les valeurs négatives dans les espaces de valeurs possibles...
    Oui et peut-être non.
    J'avais lu quelque part que SQLPro n'aime pas le UNSIGNED pour les clés mais je ne me souviens plus de la raison.

    je te conseille d'encapsuler tes requêtes dans des procédures stockées pour éviter de les renvoyer à chaque fois...
    Euh... je ne vois pas l'utilité d'une procédure stockée dans ce cas !
    Une vue serait suffisante non ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  4. #4
    Invité
    Invité(e)
    Par défaut
    merci pour vos réponses .
    En effet mon modèle est bidon et je n'ai pas pris en compte les règles d'écriture dont vous faites part car ma question n'a rien à voir avec cela.

    @ericd69 : pour la requête avec jointure : celle ci va me retourner une liste de toutes les voitures avec pour 1 voiture : 1 à "n" lignes selon que la voiture a plusieurs couleurs ou plusieurs passager. Donc, par la suite, il va falloir que je fasse un traitement php qui lira ligne par ligne le tableau et instanciera des objets en conséquence.

    Dans mon 1er exemple (avec la boucle while) j'obtiens des tableaux tout faits sans traitement php derrière, j'ai juste à les afficher.

    Ma question est : quelle est la meilleur solution, la plus optimisée ?
    D'un côté 1 requête et du traitement php, de l'autre côté plusieurs requêtes mais pas de traitement pour sortir la liste des 20 voitures.

    Merci pour vos réponses (et ne me parlez pas de notion d'écriture... ce n'est pas la question)
    Dernière modification par ced ; 09/11/2012 à 11h37.

  5. #5
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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 818
    Billets dans le blog
    14
    Par défaut
    La présentation des données est du ressort du programme applicatif et non pas du SGBD.
    Il vaut mieux ramener en une seule requête les informations à afficher et traiter le jeu de résultats en une fois dans un programme plutôt que de soumettre X requêtes au SGBD.

    Comparaison avec la vie réelle..
    Mes livres sont répartis au hasard dans des cartons situés dans le garage après mon déménagement. Je te demande d'aller les ranger dans la bibliothèque par auteur et par taille de livre. Tu vas aller chercher les livres un par un dans le garage ou apporter un maximum de cartons dans la bibliothèque et faire le tri en une seule fois ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  6. #6
    Invité
    Invité(e)
    Par défaut
    @CinePhil : Merci pour la réponse.

    Je m'en doutais un peu mais je me demandais si il y a vraiment une différence de performance ?

    Car d'un côté on demande avec 1 seule requête un tableau avec plein de lignes d'un coup (on va dire 1000) dont des éléments sont répétés inutilement + ensuite il faut traiter cet énorme tableau en php pour afficher la liste que l'on souhaite.
    Exemple de résultat d'une jointure avec 3 couleurs et des passagers avant / arrière pour 1 seule voiture :
    Opel | gris | 2 passagers avant
    Opel | gris | 3 passagers arrières
    Opel | blanche | 3 passagers arrières
    Opel | rouge | 3 passagers arrières


    Et de l'autre coté on demande plein de petites requêtes et elles nous renvoient juste ce dont j'ai besoin et donc pas de traitement php à effectuer.
    Dernière modification par ced ; 09/11/2012 à 17h11.

  7. #7
    Membre émérite
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    445
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 445
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Tu vas aller chercher les livres un par un dans le garage ou apporter un maximum de cartons dans la bibliothèque et faire le tri en une seule fois ?
    Plus le garage est loin, plus c'est handicapant.


    J'ai fait un test avec une application et une base sur un même PC :
    1000 petites requêtes (1 seule ligne) -> 0,37s
    1 grosse requête (contenant 1000 lignes) -> 0,08s


    Avec l'application sur un PC et la base sur un autre PC :
    1000 petites requêtes (1 seule ligne) -> 2.89s
    1 grosse requête (contenant 1000 lignes) -> 0,14s

    Edit :
    Ça ne doit plus être trop vrai si on lance les 1000 requêtes en parallèle...
    Tant pis...

Discussions similaires

  1. Requête sql avec jointure et table vide (ou tuple nulle)
    Par Aenur56 dans le forum Langage SQL
    Réponses: 5
    Dernier message: 29/04/2010, 14h10
  2. Construction d'une requête SQL avec jointure
    Par Didiou35 dans le forum Requêtes
    Réponses: 3
    Dernier message: 08/10/2009, 22h26
  3. Requête SQL avec jointure
    Par manu32320 dans le forum Zend_Db
    Réponses: 3
    Dernier message: 17/05/2009, 00h19
  4. Requête SQL avec jointure sur trois tables
    Par pit2121 dans le forum SQL
    Réponses: 0
    Dernier message: 19/05/2008, 20h24
  5. Comment optimiser requête SQL avec création Index
    Par schumi101 dans le forum SQL
    Réponses: 25
    Dernier message: 11/12/2007, 21h28

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