Optimisation d'une requête MySQL

Optimisation d'une requête MySQL - SQL/NoSQL - Programmation

Marsh Posté le 07-06-2010 à 14:24:55    

Bonjour à tous ! :)
 
Je poste sur ce forum afin de vous exposer le problème auquel je suis confronté et dont je ne trouve pas de solution "raisonnable". Par "raisonnable", j'entends une solution qui ne prenne pas 10 minutes à s'exécuter en prenant 100% de l'UC.
 
Tout d'abord, je vais vous présenter le contexte afin que vous puissez comprendre la ou se situe mon problème. Je dispose de 3 tables MySQL dont les noms sont :
- partenaires : Cette table contient les différents partenaires du site
- referers : Cette table contient les referers, c'est à dire le site référent qui à permis l'accès au site
- sites_partenaire : Cette table contient les sites partenaires
- inscrits : Cette table contient tous les inscrits à mon site
 
Voici le schéma (simplifié) de la base de donnée :
 
http://nsa14.casimages.com/img/2010/06/07/10060702243346490.png
 
Concrètement, un visiteur s'inscrit en tant que partenaire (une entrée est donc ajoutée dans la table partenaire), ajoute ces sites (autant d'entrées que de sites sont ajoutées dans la table site_partenaire). Ensuite, ce partenaire poste des liens de mon site sur son site. De mon côté, un script check les referers, si le referer n'est pas dans la table, il l'ajoute, sinon, il incrémente le compteur de visite provenant de ce referer dans la table referer. Si le visiteur s'inscrit sur mon site, alors une entrée est ajouté dans la table inscrits.
 
Ce que je souhaite faire, c'est mettre à jour le nombre de crédits du partenaire. Son nombre de crédits dépend du nombre de visiteurs et d'inscrits qu'il a apporté. Cependant, la mauvaise conception des tables rend la requête compliquée à mettre en oeuvre.
 
Dans l'hypothèse ou une visite rapporterait 10 crédit et une inscription 1000 crédits.
 
En gros, ce que je voudrais faire c'est un UPDATE sur la table partenaire afin de mettre à jour le nombre de credit en augmentant ce nombre de crédits de 10 x le nombre de visiteurs apporté + 1000 x le nombre d'inscrits rapportés.  
 
Actuellement, j'effectue cette mise à jour en effectuant deux requêtes mais comme explicité plus haut, ces deux requêtes prennent près de 10 minutes à 100% du CPU pour s'exécuter, ce qui n'est pas souhaitable. Je viens donc vers vous pour tenter de trouver une meilleure solution.
 
Mise à jour du nombre de crédits apportés grâce au visites :
 

Code :
  1. UPDATE partenaires
  2. SET partenaires.credit = partenaires.credit + 10*
  3.   (
  4.    SELECT SUM(referers.cpt)
  5.    FROM referers
  6.    JOIN sites_partenaire ON (site_partenaire.url LIKE CONCAT("%", referers.ndd, "%" ))
  7.    WHERE partenaire_id = partenaires.id
  8.    GROUP BY(partenaire_id)
  9.   )


 
Mise à jour du nombre de crédits apportés grâce aux inscriptions
 

Code :
  1. UPDATE partenaires
  2. SET partenaires.credit = partenaires.credit + 1000*
  3.  (
  4.   SELECT COUNT(*)
  5.   FROM inscrits
  6.   WHERE id_ref IN
  7.   (
  8.    SELECT id_ref
  9.    FROM referers
  10.    JOIN site_partenaire ON (site_partenaire.url LIKE CONCAT("%", referers.ndd, "%" ))
  11.    WHERE partenaire_id = partenaires.id
  12.   )
  13.  )


 
J'imagine que ce qui fait ralentir la requête sont les sous requêtes. D'autant plus que je souhaiterais préciser que la table "inscrits" contient plusieurs millions d'entrées.
 
Voila, dans l'espoir d'avoir été explicite et d'avoir de l'aide, je vous remercie d'avance :)
 
Encore merci de m'avoir lu.

Reply

Marsh Posté le 07-06-2010 à 14:24:55   

Reply

Marsh Posté le 07-06-2010 à 15:45:41    

Ton probleme viens probablement du LIKE CONCAT ("%" ...  
Un LIKE qui commence par un % fait un table scan a chaque fois, donc il scan ta table autant de fois qu'il ya de record a updater, donc ca prends deux plombes.
 
Il faudrai soit que tu modifies ton champ site_partenaire.url ou qu'il soit egal a referers.ndd ou trouver un moyen pour ne plus utiliser de LIKE % ... mais juste un LIKE referers.ndd + % avec un index sur url et ndd.

Reply

Sujets relatifs:

Leave a Replay

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