Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to optimize a nested query?

Tags:

Can I somehow join tables and avoid the usage of distinct in the following MySQL query. invited_by_id shows the user id of who invited this user.

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;
like image 521
vian Avatar asked Jan 29 '10 07:01

vian


People also ask

How do you optimize a poor performing query?

Steps to take to improve performance of queries: - Create all primary and foreign keys and relationships among tables. - Avoid using Select*, rather mention the needed columns and narrow the resultset as needed. - Implement queries as stored procedures. - Have a WHERE Clause in all SELECT queries.


2 Answers

I am assuming here that you are trying to get a count of how many times a user has been invited and a count of how many times that user has been invited in the past 30 days.

In this case you could do the query with a simple conditional sum as :

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

If the nulls in theCount2 will be a problem, use a coalesce as :

coalesce(sum(user2.signup_date >= NOW() - INTERVAL 30 DAY), 0)
like image 179
Mongus Pong Avatar answered Oct 11 '22 20:10

Mongus Pong


Try something like this, I changed the sub-query table names to make it a bit clearer:

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

If this is something you run often, make sure that user.invited_by_id is indexed!

like image 40
Nick Craver Avatar answered Oct 11 '22 20:10

Nick Craver