Optimisation d'une requete

Optimisation d'une requete - SQL/NoSQL - Programmation

Marsh Posté le 05-08-2008 à 13:07:41    

Bonjour,
 
J'ai un site qui ralentit à l'execution d'une requete :  
 

Code :
  1. "SELECT fights.*, p1.name AS att, p2.name AS def, p1.idpet AS attPic, p2.idpet AS defPic  FROM fights
  2.       LEFT JOIN (SELECT pets.id, pets.name, pets.idpet
  3.          FROM pets ) AS p1 ON fights.id_off=p1.id
  4.       LEFT JOIN (SELECT pets.id,pets.name, pets.idpet
  5.          FROM pets) AS p2 ON fights.id_def=p2.id
  6.       LEFT JOIN pets ON fights.id_off=pets.id
  7.       WHERE fights.etat = 0 AND pets.owner=".$id." ORDER BY time DESC LIMIT ".$page.",".$limit);


 
Les deux tables consultes sont pets ( plus de 100 000 lignes ) et fights ( environ 6000 lignes ). Or mon hebergeur m'a dit que cette requete faisait consulter environ 1 million de lignes au total ce qui fait ralentir tout mon site.
 
Avez vous une idée pour l'optimiser voir la découper en deux pour qu'à la fin je puisse récupérer les données suivantes :  
 
att
def
attPic
defPic
 
Merci de votre aide :)

Reply

Marsh Posté le 05-08-2008 à 13:07:41   

Reply

Marsh Posté le 05-08-2008 à 13:31:46    

1) vérifier que tu as bien un index sur pets.id
 
2) en oracle ca ne changerait rien mais peut-etre que en mysql ca a son importance, il n'y a pas d'interet a sous-selecter tes tables pets
 
en plus en le réécrivant on peut voir que tu attaques 2x pets en outer join sur le champ fights.id_off
encore une rajoute en relisant, si tu mets pets.owner dans ton where, alors c'est un inner join

Code :
  1. "SELECT fights.*, p1.name AS att, p2.name AS def, p1.idpet AS attPic, p2.idpet AS defPic  FROM fights
  2.          LEFT JOIN pets  AS p1 ON fights.id_off=p1.id
  3.          LEFT JOIN pets AS p2 ON fights.id_def=p2.id
  4.          LEFT JOIN pets as p3 ON fights.id_off= p3.id
  5.          WHERE fights.etat = 0 AND pets.owner=".$id." ORDER BY time DESC LIMIT ".$page.",".$limit);


Message édité par casimimir le 05-08-2008 à 13:32:28
Reply

Marsh Posté le 05-08-2008 à 14:10:39    

malgré la réécriture faite par casimimir, il reste un souci de produit cartésien au niveau de ta troisième occurence de pets.
 
t'as un filtre sur le owner_id mais c'est tout. à mon avis y'a une couille dans le potage...
 
tu essaies de faire quoi au juste ?


Message édité par MagicBuzz le 05-08-2008 à 14:10:55
Reply

Marsh Posté le 05-08-2008 à 17:52:02    

En fait le joueur lance un combat contre un autre joueur avec un de ses animaux pets. Une fois le combat lancé, cela lance cette requête pour affiché sur une page les combats lances.
 
On se retrouve ainsi avec deux colonnes : dans une colonne, l'image, le nom du pets qui a lancé le combat, et dans l'autre colonne l'image et le nom du pets contre lequel on a lancé le combat.
 
Les combats sont triés par date.
 
Seul les combats lances et pas encore acceptés ( etat = 0 ) sont affichés.

Reply

Marsh Posté le 05-08-2008 à 17:57:33    

et ça donne quoi en shootant ton p3 et en mettant "and (p1.owner = $id or p2.owner = $id)" ?

Reply

Marsh Posté le 05-08-2008 à 18:11:16    

J'obtient des pages blanches sur mon site si je fais ca.

Reply

Marsh Posté le 06-08-2008 à 09:42:58    

Bonjour
 
je pense que la condition 'LEFT JOIN pets as p3 ON fights.id_off= p3.id' ne sert a rien
et que la condition pets.owner=".$id." est erroné, elle ne fait pas référence à la table P1 ou P2 !!!
 
que se passe t'il si tu execute la requete suivante
 

Code :
  1. SELECT fights.*, p1.name AS att, p2.name AS def, p1.idpet AS attPic, p2.idpet AS defPic  FROM fights
  2.    LEFT JOIN pets  AS p1 ON fights.id_off=p1.id AND p1.owner=".$id
  3.    LEFT JOIN pets AS p2 ON fights.id_def=p2.id AND p2.owner=".$id
  4.    WHERE fights.etat = 0
  5.    ORDER BY time DESC LIMIT ".$page.",".$limit);


 
Bruno

Reply

Marsh Posté le 06-08-2008 à 10:36:02    

Ben ca me donne toujours une page blanche.
 
Il faut savoir que la première requete que j'ai donné est bonne, le site fonctionne avec mais il ralentit de trop depuis une semaine car une table est devenue trop grosse apparement.
 
Et à chaque fois que je change la requete avec vos modifs, j'obtient une page blanche à la place :(

Reply

Marsh Posté le 06-08-2008 à 10:49:18    

pareil que magicbuzz, moi je l'aurais écrite comme ca  
 

Code :
  1. SELECT  fights.*,
  2.  p1.name AS att,
  3.  p2.name AS def,
  4.  p1.idpet AS attPic,
  5.  p2.idpet AS defPic 
  6. FROM  fights
  7.  INNER JOIN pets p1 on fights.id_off=p1.id
  8.  INNER JOIN pets p2 ON fights.id_def=p2.id
  9. WHERE  fights.etat = 0
  10.  AND (p1.owner=".$id." or p2.owner=".$id." )
  11. ORDER BY time DESC


Message édité par HappyHarry le 06-08-2008 à 10:49:37
Reply

Marsh Posté le 06-08-2008 à 11:39:27    

a mon avis vu ce qu'il explique il ne faut pas de or, car il ne veut que les combats que le joueur a lancé, je suppose que id_off c'est pour id_offender et id_def pour id_defender, donc a priori le where doit cibler uniquement p1.
 
de nouveau je connais assez peu mysql mais un plan d'exécution ca éviterait 14 posts
 
ca c'est le plus logique par rapport a ton truc:
 

Code :
  1. SELECT  fights.*,
  2.   p1.name AS att,
  3.   p2.name AS def,
  4.   p1.idpet AS attPic,
  5.   p2.idpet AS defPic
  6. FROM  pets p1
  7. INNER JOIN fights f on f.id_off=p1.id
  8. INNER JOIN  on pets p2 ON f.id_def=p2.id
  9. WHERE p1.owner=".$id."
  10. and f.etat = 0
  11. ORDER BY time DESC


 
mais le vraiment plus logique serait un truc genre
 

Code :
  1. SELECT  fights.*,
  2.   p1.name AS att,
  3.   p2.name AS def,
  4.   p1.idpet AS attPic,
  5.   p2.idpet AS defPic
  6. FROM  owner o
  7. INNER JOIN fights f on f.id_off=o.id
  8. INNER JOIN pets p1 f.id_off=p1.id
  9. INNER JOIN pets p2 f.id_def=p2.id
  10. WHERE o.owner=".$id."
  11. and f.etat = 0
  12. ORDER BY time DESC


 
dans tous les cas, vérifier que tu as des index ou il faut


Message édité par casimimir le 06-08-2008 à 11:41:35
Reply

Marsh Posté le 06-08-2008 à 11:39:27   

Reply

Marsh Posté le 06-08-2008 à 11:39:31    

HappyHarry, je viens de mettre ta requete en place. Ca a l'air de fonctionner avec cependant un petit bug d'affichage car on a occulté cette ligne : LEFT JOIN pets ON fights.id_off=pets.id .
 
Du coup au lieu d'avoir que les combats lances, on se retrouve avec les lances et les recus sur la même page.
 
Dommage car sinon ca a l'air bien plus rapide. Saurait tu comment remettre cette ligne de code dans celui que tu m'as livré en dernier ?

Reply

Marsh Posté le 06-08-2008 à 11:42:15    

casimimir, le owner du pets est dans la table des pets. Ce n'est pas une table en soit. Sinon oui tu avais bien cerné le fait que je ne voulais que les combats lances, on a posté en même temps.

Reply

Marsh Posté le 06-08-2008 à 14:17:36    

cartouche31 a écrit :

HappyHarry, je viens de mettre ta requete en place. Ca a l'air de fonctionner avec cependant un petit bug d'affichage car on a occulté cette ligne : LEFT JOIN pets ON fights.id_off=pets.id .
 
Du coup au lieu d'avoir que les combats lances, on se retrouve avec les lances et les recus sur la même page.
 
Dommage car sinon ca a l'air bien plus rapide. Saurait tu comment remettre cette ligne de code dans celui que tu m'as livré en dernier ?


 
si effectivement tu veux distinguer les combats "lancés" et "reçus", réfère toi à ce que te propose casimimir

Reply

Marsh Posté le 07-08-2008 à 10:58:34    

Bonjour  
Que donne ces 2 requetes ?
 

Code :
  1. SELECT fights.*, p1.name AS att, p2.name AS def, p1.idpet AS attPic, p2.idpet AS defPic  FROM fights
  2. INNER JOIN pets  AS p1 ON fights.id_off=p1.id AND p1.owner=".$id
  3. LEFT JOIN pets AS p2 ON fights.id_def=p2.id
  4. WHERE fights.etat = 0
  5. ORDER BY time DESC LIMIT ".$page.",".$limit)


 

Code :
  1. SELECT fights.*, p1.name AS att, p2.name AS def, p1.idpet AS attPic, (select p2.idpet from pets AS p2 where fights.id_def = p2.id) AS defPic  FROM fights
  2. INNER JOIN pets  AS p1 ON fights.id_off=p1.id AND p1.owner=".$id
  3. WHERE fights.etat = 0
  4. ORDER BY time DESC LIMIT ".$page.",".$limit)


Reply

Marsh Posté le 07-08-2008 à 15:12:30    

Aucune des deux ne fonctionne bruno2607 :(  
 
Mais bon c'est pas grave pour le moment le site tourne rapidement avec la requete de HappyHarry et même si ca n'affiche pas que les defis lancés, c'est pas trop genant car ce n'est pas une page critique, en plus les joueurs savent quels sont leur combattant et ceux des adversaires dans la liste. L'important est que ca soit rapide et que ca fasse presque comme avant :)  
 
Merci à tous de votre aide en tout cas, c'est sympa de votre part et franchement ca m'a vraiment aidé car mon site était un peu bloqué a cause de ca.

Reply

Marsh Posté le 07-08-2008 à 16:35:20    

Code :
  1. Code :
  2.    1. SELECT  fights.*,
  3.    2.  p1.name AS att,
  4.    3.  p2.name AS def,
  5.    4.  p1.idpet AS attPic,
  6.    5.  p2.idpet AS defPic
  7.    6. FROM  fights
  8.    7.  INNER JOIN pets p1 on fights.id_off=p1.id
  9.    8.  INNER JOIN pets p2 ON fights.id_def=p2.id
  10.    9. WHERE  fights.etat = 0
  11.   10.  AND p1.owner=".$id."
  12.   11. ORDER BY time DESC


 
pour n'avoir que les défis lancés par le joueur

Reply

Marsh Posté le 08-08-2008 à 00:20:25    

Fais déjà un EXPLAIN de ta requête d'origine pour voir d'où peut venir le problème de perf, c'est là pour ça...

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed