mysql – 使用LEFT JOIN和ORDER BY查询… LIMIT慢,使用Filesort

我有以下查询:

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

以及您可能想要的所有索引,包括以下使用的索引:

fruit        - fruit_filter (size, status, location, date)
food_fruits  - food_type (type)
food         - food (id)
fruits_sour  - fruit_id (fruit_id)

我甚至有一些我认为可以更好地使用的索引:

food_fruits  - fruit_key (fruit_id, type)
food         - id_name (food_id, name)

不幸的是,ORDER BY子句导致临时表和filesort被使用.没有它,查询运行lickety-split.如何让这个查询不需要filesort?我错过了什么?

编辑:

解释:

最佳答案 原因是你的ORDER BY子句在字段上完成,该子字段不是用于此查询的索引的一部分.引擎可以使用fruit_filter索引运行查询,但是它必须对不同的字段进行排序,这就是当filesort进入游戏时(这基本上意味着“不使用索引排序”,这要归功于评论中的提醒).

我不知道你得到的结果是什么时候,但如果差别很大,那么我会创建一个包含中间结果的临时表,然后对其进行排序.

(顺便说一句,我不知道你为什么使用LEFT JOIN而不是INNER JOIN,为什么要使用food_fruits – 在评论中回答)

UPDATE.

尝试子查询方法,可能是(未经测试),它将排序与预过滤分开:

SELECT
    fr.date,
    fr.name,
    fr.reason,
    fr.id,
    fr.notes,
    food.name
FROM
  (
  SELECT 
    fruit.date,
    fruit.name,
    fruit.reason,
    fruit.id,
    fruit.notes,
  FROM
    fruit
  LEFT JOIN
    fruits_sour AS fs ON fruit.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)
  ) as fr
LEFT JOIN
    food_fruits AS ff ON fr.fruit_id = ff.fruit_id AND ff.type='fruit'
LEFT JOIN
    food USING (food_id)  
ORDER BY `food.name` asc
LIMIT 15 OFFSET 0
点赞