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

PHP & Base de données Discussion :

[SQL] Optimiser une jointure dans PHP


Sujet :

PHP & Base de données

  1. #1
    Invité
    Invité(e)
    Par défaut [SQL] Optimiser une jointure dans PHP
    Bonjour,

    Je voudrais optimisé mon code, quelqu'un peut m'aider et donné des suggestions.
    $querychamp = mysql_query("SELECT * FROM gagnant",$db);
    $num = mysql_num_rows($querychamp);
    if ( $num != 0) {
    while ( $gagnant = mysql_fetch_array($querychamp) ) {
    $gagnantid = $gagnant['id'];
    $cadeauxid = $gagnant['cadeaux'];
    $membreid = $gagnant['gagnant'];
    $date_mysql = $gagnant['date'];
    $date = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3-$2-$1', $date_mysql);
    $time = $gagnant['time'];
    $querychamp2 = mysql_query("SELECT * from membre WHERE id_membre = $membreid",$db);
    while ( $membre = mysql_fetch_array($querychamp2) ) {
    $nom = $membre['nom'];
    $prenom = $membre['prenom'];
    echo strtoupper(substr($nom,0,1)).
    strtolower(substr($nom,1)).' '.
    strtoupper(substr($prenom,0,1)).'.';
    }
    $querychamp3 = mysql_query("SELECT * from jeuxcompteur WHERE id = $cadeauxid",$db);
    while ( $cadeau = mysql_fetch_array($querychamp3) ) {
    $titre = $cadeau['titre'];
    echo " à gagné(e) au jeu *$titre* le $date à $time ";
    }
    echo "<br>";
    }
    } else {
    echo "Il n'y a pas de cadeaux gagnés.";
    }
    merci beaucoup,

  2. #2
    Membre régulier
    Avatar de titoon
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 71
    Points : 86
    Points
    86
    Par défaut
    Si j'ai bien compris le schéma de ta base, tu peux utiliser comme requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT * // attention aux champs "id" communs à gagnant et jeuxcompteur
    FROM gagnant g, membre m, jeuxcompteur j
    WHERE g.gagant = m.id_membre // jointure gagnant <=> membre
    AND g.cadeau = j.jeucompteur // jointure cadeau <=> jeuxcompteur

  3. #3
    Membre expert

    Profil pro
    Inscrit en
    Septembre 2002
    Messages
    1 581
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 581
    Points : 3 016
    Points
    3 016
    Par défaut
    Citation Envoyé par titoon
    Si j'ai bien compris le schéma de ta base, tu peux utiliser comme requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT * // attention aux champs "id" communs à gagnant et jeuxcompteur
    FROM gagnant g, membre m, jeuxcompteur j
    WHERE g.gagant = m.id_membre // jointure gagnant <=> membre
    AND g.cadeau = j.jeucompteur // jointure cadeau <=> jeuxcompteur
    C'est indépendant du PHP et plutôt lié directement au forum "langage SQL". Ceci dit, je ne pense pas que cette requête ci-dessus soit si optimale, pour les raisons suivantes:

    1. SELECT *, dans la mesure du possible, il faut toujours essayer d'éviter le "*" sauf si on a réellement besoin de rappatrier toutes les colonnes.
    2. Il faut préférer les mots clés de jointure tels que INNER JOIN, LEFT JOIN, RIGHT JOIN, etc...plutôt que d'effectuer celles-ci dans la clause WHERE. Théoriquement, la clause WHERE est réservée aux critères uniquement.

    Ceci dit, loin de moi de vouloir distribuer les bons points, donc, fais comme tu le sens

  4. #4
    Invité
    Invité(e)
    Par défaut
    moi j'utilise toujours '*' mais quelles sont les risques d'utiliser celui-ci ?

  5. #5
    Membre expert

    Profil pro
    Inscrit en
    Septembre 2002
    Messages
    1 581
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 581
    Points : 3 016
    Points
    3 016
    Par défaut
    Citation Envoyé par kiruban
    moi j'utilise toujours '*' mais quelles sont les risques d'utiliser celui-ci ?
    Toutes les colonnes de ta table sont rappatriées, donc plus de trafic sur le réseau, en RAM etc....Si par exemple tu as une table ayant cette structure

    Table Clients

    ID_Client
    Nom
    Prenom
    Titre
    DateNaissance
    NumIdentite
    ID_Addr
    Commentaire
    ....
    Et que tu as une portion de code qui sert à afficher uniquement les nom, prénom et titre

    Tu devrais théoriquement faire

    SELECT Nom,Prenom,Titre FROM Clients....

    Seules les informations liées à ces colonnes te seront renvoyées par le SGBD. Tu réduiras du même coup le trafic réseau et ton traitement côté PHP sera lui aussi plus rapide car moins de données.

    D'autre part, cette manière de travailler est beaucoup plus parlante dans le code car :

    - Tu sais exactement ce dont tu as besoin
    - Le fait de nommer explicitement les colonnes te renseigne déjà sur la structure de ta table.
    - Si un jour, tu modifies ta table et que tu ajoutes un champ pour usage interne qui ne devrait jamais être affiché, en utilisant "*", tu rappatrieras à chaque fois la valeur de ce champ inutilement.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par titoon
    Si j'ai bien compris le schéma de ta base, tu peux utiliser comme requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT * // attention aux champs "id" communs à gagnant et jeuxcompteur
    FROM gagnant g, membre m, jeuxcompteur j
    WHERE g.gagant = m.id_membre // jointure gagnant <=> membre
    AND g.cadeau = j.jeucompteur // jointure cadeau <=> jeuxcompteur
    j'ai essayer
    $querychamp = mysql_query("SELECT *
    FROM gagnant g, membre m, jeuxcompteur j
    WHERE g.gagnant = m.id_membre
    AND g.cadeaux = j.id",$db);
    while ( $data = mysql_fetch_array($querychamp) ) {
    print_r($data);
    $gagnantid = $gagnant['id'];
    $cadeauxid = $gagnant['cadeaux'];
    $membreid = $gagnant['gagnant'];
    $date_mysql = $gagnant['date'];
    $date = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3-$2-$1', $date_mysql);
    $time = $gagnant['time'];
    $nom = $membre['nom'];
    $prenom = $membre['prenom'];
    $titre = $cadeau['titre'];
    echo strtoupper(substr($nom,0,1)).
    strtolower(substr($nom,1)).' '.
    strtoupper(substr($prenom,0,1)).'.';
    echo " à gagné(e) au jeu *$titre* le $date à $time <br>";
    }
    vous pouvez me dire comment l'affichez car la ça ne marche pas

  7. #7
    Invité
    Invité(e)
    Par défaut
    $querychamp = mysql_query("SELECT date, time, nom, prenom, titre
    FROM gagnant g, membre m, jeuxcompteur j
    WHERE g.gagnant = m.id_membre
    AND g.cadeaux = j.id",$db);
    while ( $data = mysql_fetch_array($querychamp) ) {
    $date_mysql = $data['date'];
    $date = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3-$2-$1', $date_mysql);
    $time = $data['time'];
    $nom = $data['nom'];
    $prenom = $data['prenom'];
    $titre = $data['titre'];
    echo strtoupper(substr($nom,0,1)).
    strtolower(substr($nom,1)).' '.
    strtoupper(substr($prenom,0,1)).'.';
    echo " à gagné(e) au jeu *$titre* le $date à $time <br>";
    }
    c'est bon ça marche, vous pouvez me dire plus sur l'utilisation du INNER JOIN, LEFT JOIN, RIGHT JOIN, etc.. et montré une démonstration

    merci beaucoup

    PS: par rapport à ce que j'avais au début à maintenant j'ai perdu beaucoup de ligne en gardant le meme résultat

  8. #8
    Membre régulier
    Avatar de titoon
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 71
    Points : 86
    Points
    86
    Par défaut
    Citation Envoyé par stephane eyskens
    1. SELECT *, dans la mesure du possible, il faut toujours essayer d'éviter le "*" sauf si on a réellement besoin de rappatrier toutes les colonnes.
    2. Il faut préférer les mots clés de jointure tels que INNER JOIN, LEFT JOIN, RIGHT JOIN, etc...plutôt que d'effectuer celles-ci dans la clause WHERE. Théoriquement, la clause WHERE est réservée aux critères uniquement.
    OK pour le select *, perso je l'utilise jamais.

    Par contre, pour le second point... t'as une doc là dessus ???

    Citation Envoyé par http://dev.mysql.com/doc/refman/5.0/fr/join.html
    INNER JOIN et , (virgule) sont sémantiquement équivalents. Les deux opèrent une jointure totale sur les tables utilisées. Normalement, vous spécifiez les conditions de jointure dans la clause WHERE.
    Citation Envoyé par kiruban
    c'est bon ça marche, vous pouvez me dire plus sur l'utilisation du INNER JOIN, LEFT JOIN, RIGHT JOIN, etc.. et montré une démonstration
    Tu trouveras ton bonheur dans la doc de mysql

  9. #9
    Membre expert

    Profil pro
    Inscrit en
    Septembre 2002
    Messages
    1 581
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 581
    Points : 3 016
    Points
    3 016
    Par défaut
    Citation Envoyé par titoon
    OK pour le select *, perso je l'utilise jamais.
    Par contre, pour le second point... t'as une doc là dessus ???
    Tu peux par exemple aller voir sur sql.developpez.com

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    102
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 102
    Points : 120
    Points
    120
    Par défaut
    Salut,

    je rajouterais que de nommer uniquement les champs dont on a besoin permet d'utilser mysql_fetch_row() (le plus économique de la famille des fetch) plus facilement car on n'a pas forcement en tete la position ordinale des champs de sa tables.

    Quand au JOIN déja, il est issu de la norme SQL99 qui était venu remplacer la norme SQL92.
    Il est donc plus au gout du jour, plus clair entant qu'il confère une syntaxe explicite et dédiée aux jointures en les séparant du reste de la clause WHERE.
    En plus Il permet souvent l'economie des alias qui la surchargent.
    Et surtout plus puissant que les jointures en clause where.
    JE ne vais pas me répéter je vous renvoie a ce topic ou je donne quelques exemples simples.
    http://www.developpez.net/forums/sho...d.php?t=191918 (message #8)

    Sinon ben voila la version JOIN du présent problème (je part du principe qu'aucun nom de champ sité dans la requete n'est commun à 2 tables =>aucun d'alias)
    J'ai changé l'ordre d'apparition des tables, afin de pouvoir enfiler les tables comme des perles dans ma requete (on commence toujours par une table a l'extrémité pour pouvoir enchainer les JOIN):
    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
     
    $querychamp = mysql_query("SELECT date, time, nom, prenom, titre 
    FROM membre JOIN gagnant on(id_membre=gagnant)
    JOIN jeuxcompteur ON (cadeaux=id)",$db);
    while ( $data = mysql_fetch_array($querychamp) ) {
    $date_mysql = $data['date'];
    $date = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3-$2-$1', $date_mysql);
    $time = $data['time'];
    $nom = $data['nom'];
    $prenom = $data['prenom'];
    $titre = $data['titre'];
    echo strtoupper(substr($nom,0,1)).
    strtolower(substr($nom,1)).' '.
    strtoupper(substr($prenom,0,1)).'.';
    echo " à gagné(e) au jeu *$titre* le $date à $time <br>";
    }
    il n'y a pas de sotte existence

  11. #11
    Membre régulier
    Avatar de titoon
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 71
    Points : 86
    Points
    86
    Par défaut
    Erf, désolé, je suis en mysql 3.32.58, et cette version semble ne pas connaitre le JOIN seul... Je ne sais pas comment il se comporte (équivalent de LEFT JOIN ?)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    mysql> SELECT date, time, nom, prenom, titre
        -> FROM membre JOIN gagnant ON (id_membre = gagnant)
        -> JOIN jeuxcompteur ON (cadeaux = id);
    ERROR 1064: You have an error in your SQL syntax near 'ON (id_membre = gagnant)
    JOIN jeuxcompteur ON (cadeaux = id)' at line 2

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    102
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 102
    Points : 120
    Points
    120
    Par défaut
    Salut,

    effectivement essaye ca:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT date, time, nom, prenom, titre 
    FROM membre LEFT JOIN gagnant on(id_membre=gagnant)
    AND gagnant IS NOT NULL
    LEFT JOIN jeuxcompteur ON (cadeaux=id)
    la condition is not null, permet a la requete de ne pas remonter également des lignes d'utilisateur qui n'ont pas gagné, (les champs correspondant a la table gagnant seraient comblés a null).

    tu comprendras visuellement la finesse du LEFT JOIN en essayant d'abord sans le "AND gagnant IS NOT NULL " et ensuite avec.
    la différence entre les retours te permettra de comprendre l'interet de jouer avec les LEFT JOIN et RIGHT JOIN.
    il n'y a pas de sotte existence

Discussions similaires

  1. language SQL - Copier une ligne dans autre table
    Par fxd dans le forum Langage SQL
    Réponses: 1
    Dernier message: 26/10/2005, 18h16
  2. Réponses: 7
    Dernier message: 05/10/2005, 18h06
  3. Optimiser les jointures dans des requêtes
    Par klereth dans le forum PostgreSQL
    Réponses: 12
    Dernier message: 23/04/2005, 17h29
  4. [PL/SQL] Charger une table dans une collection
    Par nosnoss dans le forum Oracle
    Réponses: 10
    Dernier message: 03/03/2005, 17h56
  5. Comment optimiser une jointure ?
    Par seb_asm dans le forum Administration
    Réponses: 21
    Dernier message: 25/06/2004, 16h42

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