3

这是一个大约需要 1ms 才能完成的 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)查询再次需要 1 毫秒。

当查询很慢时,我添加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 进行第二次查询(如上面的查询),我可以得到我想要的需要在不到 10 毫秒。

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

4

1 回答 1

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;
于 2013-06-04T15:17:22.993 回答