使用ORDER BY时,MySQL查询变得非常慢

时间:2013-06-04 13:01:32

标签: mysql performance

这是一个大约需要1毫秒才能完成的mysql查询:

SELECT SQL_NO_CACHE DISTINCT invoice.*,
GROUP_CONCAT(DISTINCT line.guid) as line 
FROM invoice  
LEFT JOIN ligne ON line.invoice = invoice.guid 
GROUP BY invoice.guid 
WHERE acompte = 1
LIMIT 0, 100;

如果我将ORDER BY invoice.date添加到查询中,它会变得非常慢并且需要大约3秒才能完成。

如果我删除LEFT JOIN(以及GROUP_CONCAT),则查询会再次花费1ms。

我添加EXPLAIN以查看MySQL在查询速度缓慢时正在做什么,我可以看到它正在使用临时文件:

1   SIMPLE  invoice index   NULL    PRIMARY 4   NULL    25385   Using temporary; Using filesort
1   SIMPLE  line    ref invoice invoice 5   gestixi.invoice.guid    1   Using index

我确信有一种方法可以加快查询速度,但我无法找到它。有什么想法吗?

请注意,我无法在date上添加索引(顺便说一下,这不会改变任何内容)因为我希望我的用户能够对表的每个字段进行排序。

另请注意,invoice.guidline.invoiceline.guidacompte已编入索引。

修改

如果我在没有LEFT JOIN的情况下进行第一次查询但是使用ORDER BY子句来获取我想要的行的ID,然后在WHERE子句中使用这些id进行第二次查询(如上所述),我可以在不到10ms的时间内得到我需要的东西。

这让我相信它必须是一种在不添加索引的情况下加速查询的方法。

1 个答案:

答案 0 :(得分:1)

我担心如果你必须允许你的用户对任何字段进行排序(并且这种排序使用索引),那么你需要为每种可能的排序索引。根据定义,不可能做到这一点。对给定行进行排序只能使用此行上的索引。

我在这里看到的选择很少。要么减少要排序的行数(25k行的结果集有点大,你的用户真的需要那么多行吗?)或者不允许对所有行进行排序。

请注意,查询通常能够按表使用多个索引。正如其他人所建议的那样,复合索引对于你提到的查询更好,尽管我宁愿建议相反的顺序((guid, date))(查询首先需要选择每个guid,然后,对于每个其中,对相应的行进行排序。)

还在line(guid, acompte, invoice)上添加索引。

(以上关于索引假设MyISAM表的建议)

在优化查询本身方面,考虑到简单的执行计划,几乎没有什么可做的。

使用此版本可能会获得更好的结果,或者您可能不会:

SELECT
    invoice.*, -- DISTINCT is redudant here because of the GROUP BY clause
    GROUP_CONCAT(ligne_acompte.guid) as line  -- DISTINCT is (presumably) redundant here because guid is (presumably) unique
FROM invoice  
LEFT JOIN (
    SELECT guid, invoice
    FROM line
    WHERE acompte = 1
) AS ligne_acompte ON ligne_acompte.invoice = invoice.guid 
GROUP BY invoice.guid
ORDER BY invoice.date;