1

我仍然无法理解如何阅读、理解和优化 MySQL 解释。我知道在 orderby 列上创建索引,但仅此而已。因此,我希望您能帮助我调整此查询:

EXPLAIN
SELECT specie.id, specie.commonname, specie.block_description, maximage.title,
       maximage.karma, imagefile.file_name, imagefile.width, imagefile.height,
       imagefile.transferred
FROM specie
INNER JOIN specie_map ON specie_map.specie_id = specie.id
INNER JOIN (
    SELECT *
    FROM image
    ORDER BY karma DESC
) AS maximage ON specie_map.image_id = maximage.id
INNER JOIN imagefile ON     imagefile.image_id = maximage.id
                        AND imagefile.type = 'small'
GROUP BY specie.commonname
ORDER BY commonname ASC
LIMIT 0 , 24 

这个查询的作用是找到一个物种业力最大的照片。你可以看到这个live的结果:

http://www.jungledragon.com/species

我有一个物种表、一个图像表、一个介于两者之间的映射表和一个图像文件表,因为每个图像有多个图像文件(格式)。

解释输出:

在此处输入图像描述

对于 specie 表,我在其主要 id 和字段 commonname 上有索引。对于图像表,我在它的 id 和 karma 字段上有索引,还有一些与这个问题无关的索引。

这个查询目前需要 0.8 到 1.1 秒,在我看来这太慢了。我怀疑正确的索引会加速很多倍,但我不知道是哪一个。

4

3 回答 3

1

如果你能提供表结构和索引会更好。我想出了这个替代方案,如果你能试试这个并告诉我会发生什么,那就太好了(我很好奇!):

SELECT t.*, imf.* FROM (
  SELECT s.*, (SELECT id FROM image WHERE karma = MAX(i.karma) LIMIT 1) AS max_image_id 
  FROM image i 
  INNER JOIN specie_map smap ON smap.image_id = i.id
  INNER JOIN specie s ON s.id = smap.specie_id
  GROUP BY s.commonname 
  ORDER BY s.commonname ASC
  LIMIT 24
) t INNER JOIN imagefile imf
ON t.max_image_id = imf.image_id AND imf.type = 'small' 
于 2012-03-25T14:19:59.390 回答
1

真正的问题是没有必要优化 MySQL 解释。通常有一个查询(或多个查询)是您希望提高效率的,并且EXPLAIN是一种查看查询执行是否会按您预期发生的方法。

那就是您需要了解执行计划的外观和原因,并将其与EXPLAIN命令的结果进行比较。要了解计划的外观,您应该了解MySQL 中的索引是如何工作的

同时,您的查询是一个棘手的查询,因为使用它的高效索引有一些限制:a)同时排序和一个表中的字段,b)从另一个表中找到每个组中的最后一个元素(后者是棘手的任务本身)。由于您的数据库相当小,您很幸运当前的查询相当快(尽管您认为它很慢)。

我会以一种有点老套的方式重写查询(我假设每个物种至少有一张照片):

SELECT
   specie.id, specie.commonname, specie.block_description,
   maximage.title, maximage.karma,
   imagefile.file_name, imagefile.width, imagefile.height, imagefile.transferred
FROM (
    SELECT s.id,
           (SELECT i.id
            FROM specie_map sm
            JOIN image i ON sm.image_id = i.id
            WHERE sm.specie_id = s.id
            ORDER BY i.karma DESC
            LIMIT 1) as image_id
    FROM specie s
    ORDER BY s.commonname
    LIMIT 0, 24
) as ids
JOIN specie
  ON ids.id = specie.id
JOIN image as maximage
  ON maximage.id = ids.image_id
JOIN imagefile
  ON imagefile.image_id = ids.image_id AND imagefile.type = 'small';

您将需要以下索引:

  • (commonname)specie
  • 复合(specie_id, image_id)specie_map
  • 复合(id, karma)image
  • 复合(image_id, type)imagefile

分页现在应该发生在子查询中。

这个想法是在仅使用 id 操作的子查询中进行复杂的计算,并在顶部连接其余数据。数据将按照子查询结果的顺序进行排序。

于 2012-03-25T15:02:32.507 回答
1

我认为通过摆脱子查询,你会走得很好。查看“解释”结果的第一行和最后一行 - 它正在将整个“图像”表复制到临时表中。您可以通过将子查询替换为最后一个子句INNER JOIN image并移至ORDER BY karma DESC最后一个ORDER BY子句来获得相同的结果:

SELECT specie.id, specie.commonname, specie.block_description, maximage.title,
       maximage.karma, imagefile.file_name, imagefile.width, imagefile.height,
       imagefile.transferred
FROM specie
INNER JOIN specie_map ON specie_map.specie_id = specie.id
INNER JOIN image AS maximage ON specie_map.image_id = maximage.id
INNER JOIN imagefile ON     imagefile.image_id = maximage.id
                        AND imagefile.type = 'small'
GROUP BY specie.commonname
ORDER BY commonname ASC, karma DESC
LIMIT 0 , 24 
于 2012-03-25T21:41:02.683 回答