I have this rather simple SQL query, but it takes almost a minute to execute:
SELECT
i.id,
...,
a.id AS albums_id,
...,
u.id AS users_id,
...
FROM
images i
LEFT JOIN albums a ON i.albums_id = a.id
LEFT JOIN users u ON a.users_id = u.id
WHERE
a.access = 'public'
AND i.num_of_views > 0
ORDER BY
i.num_of_views DESC
LIMIT
0, 60
Result of EXPLAIN for the above query:

Tables involved:
images (~4,822,000 rows), albums (~149,000 rows), users (~43,000 rows)
Relevant indexes:
albums: access(access,num_of_images,album_time), access_2(access,num_of_images,num_of_all_comments,album_time), users_id(users_id,album_time)
images: browser_2(num_of_views), albums_id(albums_id,image_order)
All tabels are InnoDB, running on MySql v5.1.47
So how do I bring this down to under a second?
Please leave a comment if you need any additional info.
edit: users table can be joined either with albums or images does not matter to me.
edit2: moving a.access = 'public' from WHERE to JOIN does indeed solve my problem, but the results returned are not correct (I get images from albums that are not public), putting the a.access ... in both WHERE and JOIN slows the query down even more than before.
I believe there’s a little confusion going on here w/r/t the impact that a filter can have on a LEFT JOIN vs an INNER JOIN.
Jan, if what you are trying to ask in your query is “Get all images for all albums that are public, and get the users of those albums as well” then you do not want a left join, you want an inner join. A left join will return all images for all albums, but it will also return all images that have no matching album. You can add “and a.id IS NOT NULL” but that’s the same as an INNER JOIN.
I believe what you want is the following:
If you left join albums to users you could return all albums that don’t have users. Not sure which one you want.