Trying to optimize this query, with a corollated subquery
SELECT g.*, g.instaLikes + ( SELECT COUNT( * ) FROM gallery_likes AS l WHERE l.gallery_id = g.id ) AS likes
FROM gallery AS g
WHERE ( STATUS = 'approved' )
ORDER BY g.moderated_at DESC , g.id ASC
The SELECT without the subquery is very fast, and when I try a LEFT JOIN its even slower.
SELECT g.*, (g.instaLikes + COUNT( l.id ) ) AS likes
FROM gallery AS g
LEFT JOIN gallery_likes AS l ON ( g.id = l.gallery_id )
WHERE ( STATUS = 'approved)
GROUP BY g.id
ORDER BY g.moderated_at DESC , g.id ASC
The option that seems to be fastest is to do the queries separately and then add the fields together in a PHP loop, since I can run the subquery once, rather than n times in gallery.
Currently there are 2000 rows in gallery and 15000 rows in gallery_likes. I figured that I wouldn’t need to optimize yet, because those numbers seem low, but the first query takes 20-30 seconds and the LEFT JOIN takes 100+ seconds!
Doing separate queries and joining the data in PHP isn’t a bad idea. But if you wanted to do essentially the same thing in SQL, you can. You can treat a query just like a table (i.e. join on it), they are called derived tables. This is often a quicker and easier way to optimize these types of queries.
That is grouping all of the records from gallery_likes, which is probably very inefficient. So you should add some sort of filter. Event if the sub-select (derived table) joins on the gallery and use the same filter as the outer query. This almost like your second query, but it’s grouping the data before joining. Rather than joining and then grouping.
Often times this is a great solution when you need to join on summary data (i.e. group by), but sometimes it can be inefficient. You can usually tell by the EXPLAIN.