In the slow case, MySQL is making an assumption that the index on STATUS
will greatly limit the number of users
it has to sort through. MySQL is wrong. Presumably most of your users are ACTIVE
. MySQL is picking up 50k user rows, checking their ACCESS_ID
, joining to MIGHT_FLOCK
, sorting the results and taking the first 100 (out of 50k).
In the fast case, you have told MySQL it can't use either index on USERS
. MySQL is using its next-best index, it is taking the first 100 rows from MIGHT_FLOCK
using the STREAK
index (which is already sorted), then joining to USERS
and picking up the user rows, then checking that your users are ACTIVE
and have an ACCESS_ID
at or above 8. This is much faster because only 100 rows are read from disk (x2 for the two tables).
I would recommend:
- drop the index on
STATUS
unless you frequently need to retrieveINACTIVE
users (notACTIVE
users). This index is not helping you. - Read this question to understand why your sorts are so slow. You can probably tune InnoDB for better sort performance to prevent these kind of problems.
- If you have very few users with
ACCESS_ID
at or above 8 you should see a dramatic improvement already. If not you might have to use STRAIGHT_JOIN in your select clause.
Example below:
SELECT *
FROM MIGHT_FLOCK mf
STRAIGHT_JOIN USERS u ON (u.USER_ID = mf.USER_ID)
WHERE u.STATUS = 'ACTIVE' AND u.ACCESS_ID >= 8 ORDER BY mf.STREAK DESC LIMIT 0,100
STRAIGHT_JOIN
forces MySQL to access the MIGHT_FLOCK
table before the USERS
table based on the order in which you specify those two tables in the query.
To answer the question "Why did the behaviour change" you should start by understanding the statistics that MySQL keeps on each index: http://dev.mysql.com/doc/refman/5.6/en/myisam-index-statistics.html. If statistics are not up to date or if InnoDB is not providing sufficient information to MySQL, the query optimiser can (and does) make stupid decisions about how to join tables.