0

HI I have the following query:

SELECT PAS_User.user_user_id, 
PAS_User.user_city, 
PAS_User.user_company, 
PAS_User.user_country, 
PAS_User.user_account_type, 
PAS_User.user_account_premium, 
PAS_User.user_sign_up_date, 
PAS_User.user_first_name, 
PAS_User.user_last_name, 
PAS_User.user_avatar_url, 
PAS_User.user_cover_image_url, 
PAS_User.user_bio, 
PAS_User.user_sector, 
PAS_User.user_job_type, 
(SELECT COUNT(*) FROM `PAS_Follow` WHERE `folw_follower_user_id`=:sid) AS user_following_count,
(SELECT COUNT(*) FROM `PAS_Follow` WHERE `folw_followed_user_id`=:sid) AS user_followed_count,
(SELECT COUNT(*) FROM `PAS_Post` WHERE `post_user_id`=:sid) AS user_post_count, 
(SELECT COUNT(*) FROM `PAS_Follow` WHERE `folw_follower_user_id`=:sid AND `folw_followed_user_id`=:cid) AS user_this_user_is_following, 
(SELECT COUNT(*) FROM `PAS_Follow` WHERE `folw_followed_user_id`=:cid AND `folw_follower_user_id`=:sid) AS user_this_user_is_followed 
FROM PAS_User 
WHERE `PAS_User`.`user_user_id`=:sid

Which is designed to get counts from other tables for a profile page and the basic user details where :sid = 1 and :cid = 2.

The question is, is there any better way of achieving this in perhaps a smaller query or in a cleaner way?

The tables used are

PAS_User , PAS_Follow & PAS_Post

Thanks

Justin

2
  • Why do you repeat that PAS_User. thing so much? Commented Jun 3, 2013 at 14:00
  • One can never be too verbose. While it's technically not needed here it doesn't cost any performance. Commented Jun 3, 2013 at 14:13

2 Answers 2

1

You should denormalize all those counter fields and only update them when a user posts something, or presses a Follow button. Your current query is going to blow up your database server in the foreseeable future if your website gets actual active users.

Sign up to request clarification or add additional context in comments.

2 Comments

I thought about that however the query is designed so that as a user arrives at a profile the information is live and realtime however I will look into Denormailsation
It's the only possible optimization, and if you read the linked page you should pay extra attention to the last line: "Denormalization techniques are often used to improve the scalability of Web applications". That's what it's for - preventing server problems and speeding up queries, in situations where fast responses are of critical importance.
0

I'm going to be honest. I don't really like nested select statements (select within select). However, in your case, the alternative may be uglier and prone to performance errors. The temptation is to do something like:

select . . .
from PAS_User u left outer join
     (select folw_foller_user_id, count(*) as user_following_count
      from PAS_Follow pf
      group by folw_foller_user_id
     ) pf
     on pf.folw_foller_user_id = u.user_user_id left outer join
     . . .

Fine. But this will perform much worse than your original query, because of the outside filter on user_user_id. To fix this, you would repeat the condition in the subquery:

select . . .
from PAS_User u left outer join
     (select folw_foller_user_id, count(*) as user_following_count
      from PAS_Follow pf
      where folw_foller_user_id = :sid
      group by folw_foller_user_id
     ) pf
     on pf.folw_foller_user_id = u.user_user_id left outer join
     . . .

Or even:

select . . .
from PAS_User u cross join
     (select count(*) as user_following_count
      from PAS_Follow pf
      where folw_foller_user_id = :sid
     ) pf
     on pf.folw_foller_user_id = u.user_user_id left outer join
     . . .

And I might even argue that repeating the condition in one subquery would be good. I cannot make that argument for five subqueries.

To make this clear, the best syntax is to user window functions:

select . . .
       count(*) over (partition by folw_fllower_user_id) as user_following_count,
       . . .

Alas, MySQL does not support window functions. A very reasonable replacement, in my opinion, are subqueries (which would normally be correlated). This supports your initial syntax.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.