I have the following query:
SELECT
fruit.date,
fruit.name,
fruit.reason,
fruit.id,
fruit.notes,
food.name
FROM
fruit
LEFT JOIN
food_fruits AS ff ON fruit.fruit_id = ff.fruit_id AND ff.type='fruit'
LEFT JOIN
food USING (food_id)
LEFT JOIN
fruits_sour AS fs ON fruits.id = fs.fruit_id
WHERE
(fruit.date < DATE_SUB(NOW(), INTERVAL 180 DAY))
AND (fruit.`status` = 'Rotten')
AND (fruit.location = 'USA')
AND (fruit.size = 'medium')
AND (fs.fruit_id IS NULL)
ORDER BY `food.name` asc
LIMIT 15 OFFSET 0
And all the indexes you could ever want, including the following which are being used:
fruit - fruit_filter (size, status, location, date)
food_fruits - food_type (type)
food - food (id)
fruits_sour - fruit_id (fruit_id)
I even have indexes which I thought would work better which are not being used:
food_fruits - fruit_key (fruit_id, type)
food - id_name (food_id, name)
The ORDER BY clause is causing a temporary table and filesort to be used, unfortunately. Without that, the query runs lickety-split. How can I get this query to not need to filesort? What am I missing?
EDIT:
The Explain:

The reason for this is your
ORDER BYclause which is done on the field which is not part of index used for this query. The engine can run the query using thefruit_filterindex, but then it has to sort on the different field, and that's whenfilesortcomes into play (which basically means "sort without using index", thanks to the reminder in comments).I don't know what times you are getting as a result, but if the difference is a lot, then I would create a temporary table with intermediate results and sorted it afterwards.
(By the way, i am not sure why do you use
LEFT JOINinstead ofINNER JOINand why do you usefood_fruits- answered in comments)UPDATE.
Try subquery approach, may be (untested), which splits sorting from pre-filtering: