我仍然无法理解如何阅读,理解和优化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
这个查询的作用是找到具有最多业力的照片。你可以看到这个直播的结果:
http://www.jungledragon.com/species
我有物种表,图像表,中间的映射表和图像文件表,因为每个图像有多个图像文件(格式)。
解释输出:
对于specie表,我的主要ID和字段commonname都有索引。对于图像表,我在其id和karma字段上有索引,还有一些与此问题无关的索引。
此查询目前需要0.8到1.1秒,这在我看来太慢了。我怀疑正确的索引会加快这个速度,但我不知道哪一个。
答案 0 :(得分: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'
答案 1 :(得分:1)
真正的问题是没有必要优化MySQL解释。通常会有一个查询(或多个查询),您希望它是高效的,EXPLAIN
是一种查看查询执行是否会按预期发生的方式。
那就是你需要了解执行计划的外观和原因,并将其与EXPLAIN
命令的结果进行比较。要了解计划的外观,您应该了解how indexes in MySQL work。
与此同时,你的查询是一个棘手的问题,因为对于使用它的有效索引有一些限制:a)同时排序和来自一个表的字段,和b)来自另一个表的finding the last element in each group(后者是一个棘手的任务本身)。由于您的数据库相当小,您很幸运,您当前的查询速度相当快(尽管您认为它很慢)。
我会以一种hacky方式重写查询(我假设每个物种至少有一个foto):
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操作的子查询中进行复杂计算,并在顶部连接其余数据。数据将按子查询结果的顺序排序。
答案 2 :(得分:1)
我认为通过摆脱子查询你会走得很好。查看“explain”结果的第一行和最后一行 - 它将整个“image”表复制到临时表中。您可以通过将子查询替换为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