【问题标题】:MySQL query become really slow when using ORDER BY使用 ORDER BY 时 MySQL 查询变得非常慢
【发布时间】:2013-06-04 13:01:31
【问题描述】:

这是一个大约需要 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),查询又需要 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 毫秒的时间内得到我需要的东西。

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

【问题讨论】:

  • 尝试在invoice.date 字段上添加索引,因为它将在您使用 order by 子句时使用。用索引检查order by子句的解释,检查是否使用..
  • 正如我所说,我不想在invoice.date 上添加索引,因为如果这样做,我将不得不为我的表的所有字段添加索引。无论如何,我尝试在其上添加一个索引并且它没有被使用(并且没有改变任何东西)。
  • 好吧错过了你的意思...无论如何尝试在invoice.date, invoice.guid上创建复合索引,如果未使用此索引,则尝试使用use index明确告诉查询优化器使用它

标签: mysql performance


【解决方案1】:

恐怕如果您必须允许您的用户对任何字段进行排序(并让这种排序使用索引),那么您需要为每种可能的排序设置一个索引。根据定义,不可能这样做。对给定行进行排序只能使用该行上的索引。

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

请注意,一个查询通常能够按表使用多个索引。正如其他人所建议的那样,复合索引更适合您提到的查询,尽管我宁愿建议相反的顺序((guid, date))(查询首先需要选择每个guid,然后对每个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;

【讨论】:

  • 我只要求前 100 行而不是 25k。关于索引,我不确定这是不是问题,因为正如我所说,如果我删除 LEFT JOIN(但保留 ORDER BY),查询会非常快。我已经尝试了您的查询建议,但不幸的是,它比我的要糟糕得多。无论如何感谢您的帮助:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-15
  • 1970-01-01
  • 2019-09-02
  • 1970-01-01
相关资源
最近更新 更多