2009-05-21 4 views
0

J'essaie ici de trouver essentiellement des utilisateurs qui ont des régions sportives & ciblées par une activité. Dans la table acces [users] il y a environ 17K utilisateurs. Chacun peut avoir un certain nombre d'intérêts sportifs et une région.Insight sur une optimisation de requête

Ici, la requête recherche pour chaque utilisateur ayant un sport & une région au moins ciblée via les activités. Les sports peuvent être jusqu'à 75 lorsque nous sélectionnons chacun d'eux [pas très bon avec une requête IN].

SELECT a.user, pp.courriel 
FROM acces a 
LEFT JOIN acces_profil_sport ap ON ap.id = a.id 
LEFT JOIN profil_perso pp ON pp.id = a.id 
WHERE ap.sport_id IN 
    (
    SELECT ac.sport_id 
    FROM activite_sport ac 
    RIGHT JOIN activite a ON a.activite_id = ac.activite_id AND a.is_cron = 1 AND a.cron_processed = 0 
    ) 
    AND pp.region_id IN 
    (
    SELECT ar.region_id 
    FROM activite_region ar 
    RIGHT JOIN activite a ON a.activite_id = ar.activite_id AND a.is_cron = 1 AND a.cron_processed = 0 
) 
GROUP BY a.id 

Si je supprime la recherche de sport, la requête prend contournements 30 secondes pour exécuter. Sinon cela prend tout à fait pour toujours et utilise environ 99% de la proc avec mysql.

Des conseils pour vous aider?

[modifier: structure Tableau]
d'accès: id (clé primaire), l'utilisateur, PERSO _ id (touche clé/étranger à profil _ perso [perso _ id]) [quelques-autres champs]
profil _ perso: perso _ id (clé primaire) courriel, région _ id, id (clé étrangère acces [id]) [d'autres domaines]
accès _ profil _ sport: id/sport _ id (double clé primaire), niveau _ id (clé double avec sport _ id)

+1

Pourriez-vous énumérer les tables avec lesquelles vous travaillez et quelles sont les colonnes? –

+0

Vos tables sont-elles correctement indexées? Bien que cette requête ne soit pas géniale, il ne semble pas que cela prenne * long * sur le jeu de données relativement petit avec lequel vous travaillez. –

+0

Vous ne nous avez pas donné 2 des tables dans cette édition. Me montrer un «expliquer» sur cette question donnera également beaucoup de perspicacité quant à où un index est probablement manquant. –

Répondre

4

I soupçonnez que vos index sont faux. Si vous imprimez un expliquer sélectionnez ..., je peux mieux commenter. En outre, je suis curieux de savoir pourquoi vous faites des jointures et des sous-sélections gauche/droite.

Il me semble que ce devrait être des jointures normales puisque les deux jointures à gauche ne fonctionneront que si elles existent. Si elles sont nulles, vous n'obtiendrez pas de ligne à cause de la correspondance de sous-sélection requise. En ce qui concerne les jointures de droite, vous avez besoin du bit ar, qui ne fait pas partie du côté droit. Je devrais soit les supprimer, soit les rendre aussi droites. Je suppose que puisque vous vérifiez ce qui ressemble à un travail cron non traité, vous voulez les garder.

SELECT a.user, pp.courriel 
FROM acces 
JOIN acces_profil_sport ap ON ap.id = a.id 
JOIN profil_perso pp ON pp.id = a.id 
JOIN activite_sport ac ON ac.sport_id = ap.sport_id 
JOIN activite a1 ON a.activite_id = ac.activite_id AND a.is_cron = 1 AND a.cron_processed = 0 
JOIN activite_region ar ON ar.region_id = pp.region_id 
JOIN activite a2 ON a.activite_id = ar.activite_id AND a.is_cron = 1 AND a.cron_processed = 0 
+0

Ça va être traité par un cron tous les soirs ... une sorte de mailinglist-ish – Erick

+0

Nice one! seulement 0.4s! c'est un gardien merci! – Erick

+0

Neato, à peu près ce que j'allais suggérer, belle solution! –

0

Avez-vous des indices sur is_cron et cron_processed? Cela pourrait aider à accélérer les choses.

0
SELECT acces.user, courriel 
FROM acces 
JOIN profil_perso ON acces.id = profil_perso.id 
WHERE EXISTS (SELECT 1 FROM acces_profil_sport JOIN activite_sport on acces_profil_sport.sport_id = activite_sport.sport_id JOIN activite ON activite.activite_id = activite_sport.activite_id WHERE is_cron = 1 AND cron_processed = 0 AND acces_profil_sport.id = profil_perso.id) 
AND EXISTS (SELECT 1 FROM activite_region JOIN activite ON activite_region.activite_id = activite.activite_id WHERE is_cron = 1 AND cron_processed = 0 AND activite_region.region_id = profil_perso.region_id); 
+0

Pourquoi utiliser une sous-sélection où une jointure le résout? Les sous-sélections ont tendance à créer plus de frais généraux et, dans certains cas, à fonctionner sensiblement plus lentement. –

+0

Comme je l'ai mentionné dans un commentaire ci-dessus, je pense qu'il pourrait y avoir un 'distinct' requis pour utiliser simplement les jointures. Utiliser un "where exists" pour joindre les tables fonctionne bien dans la plupart des DB, même si j'admets que je n'utilise pas beaucoup MySQL et je ne savais pas que c'était quelque chose à éviter là-bas. – araqnid

Questions connexes