2010-01-29 5 views
5

Puis-je joindre des tables et éviter l'utilisation de distinct dans la requête MySQL suivante? Invite_by_id affiche l'identifiant de l'utilisateur qui a invité cet utilisateur.Comment optimiser une requête imbriquée?

SELECT 
    user1.id, count(distinct user2.id) AS theCount, count(distinct user3.id) AS theCount2 
FROM 
    users AS user1 
LEFT OUTER JOIN 
    users AS user2 ON user2.invited_by_id=user1.id 
LEFT OUTER JOIN (
    SELECT id, invited_by_id FROM users WHERE signup_date >= NOW() - INTERVAL 30 DAY 
) AS user3 ON user3.invited_by_id=user1.id 
GROUP BY user1.id; 
+0

Pourquoi auriez-vous besoin de distinct? Il me semble que l'utilisateur X ne devrait être autorisé que par l'utilisateur Y * one * time. –

+0

@Lieven Puisque la table est jointe deux fois, vous pouvez obtenir des lignes en double. –

Répondre

1

Essayez quelque chose comme ceci, j'ai changé les noms de table de sous-requête pour le rendre un peu plus clair:

Select 
    user.id, 
    all_time.total AS theCount, 
    last_month.total AS theCount2 
From users AS user 
Left Outer Join 
    (Select Count(id) as total, invited_by_id 
    From users 
    Group By invited_by_id) as all_time 
     On all_time.invited_by_id = user.id 
Left Outer Join 
    (Select Count(id) as total, invited_by_id 
    From users 
    Where signup_date >= NOW() - INTERVAL 30 DAY 
    Group By invited_by_id) AS last_month 
     On last_month.invited_by_id = user.id 

Si c'est quelque chose vous courez souvent, assurez-vous que user.invited_by_id est indexé!

1

Si vous utilisez une version de MySQL supérieure à 5.0.37 vous un Profiler à votre disposition qui pourrait vous donner une assez bonne idée de l'endroit où les goulots d'étranglement sont sur toute question. Cela pourrait être un bon point de départ - vous pourriez peut-être modifier la sortie dans la question initiale si vous n'êtes pas sûr de la meilleure façon de l'interpréter.

+0

Il est sur mysql. –

+0

Bon point, aucune idée de pourquoi j'ai tapé la mauvaise chose là-bas. – glenatron

+0

Ah ... C'est beaucoup plus logique maintenant! :) –

3

Je suppose ici que vous essayez de connaître le nombre de fois qu'un utilisateur a été invité et le nombre de fois que cet utilisateur a été invité au cours des 30 derniers jours.

Dans ce cas, vous pouvez faire la requête avec une simple somme conditionnelle:

select user1.id, count(user2.id) as tehCount, sum(user2.signup_date >= NOW() - INTERVAL 30 DAY) as theCount2 
from users as user1 
left outer join users as user2 on user2.invited_by_id = user1.id 
group by user1.id 

Si les valeurs NULL theCount2 sera un problème, utilisez un soudent comme:

coalesce(sum(user2.signup_date >= NOW() - INTERVAL 30 DAY), 0)