如何在连接多个表的查询中优化MySQL“Order By Limit 1”?

问题描述:

所以我有这样的查询:如何在连接多个表的查询中优化MySQL“Order By Limit 1”?

SELECT tablea.name, tablea.views from tablea inner 
join tableb on (tablea.id = tableb.id and tablea.balance > 0) 
order by tablea.views asc limit 1 

然而,问题是,当我运行它,它运行很慢(4+秒)。 有趣的是,当'order by'子句被删除时,保持极限1,它运行在0.005秒(大约)。

更有趣的是:当我不加入它TABLEB,即:

SELECT tablea.name, tablea.views from tablea 
where tablea.balance > 0 
order by tablea.views asc limit 1 

查询在通常为0.005秒运行一次。

注:

  • 在表A的列的观点被索引
  • 表A表B和在ID方面1对1的关系,并大致具有行的相同的量。

为什么第一个查询,第一个查询的'order by'被删除,第二个查询的性能有如此大的差异?

无论如何,当连接两个表时,排序要快得多吗?

+1

你可以在原始连接查询上运行'EXPLAIN'吗?让我们看看那里实际发生了什么。 –

+0

有关性能的问题始终需要所有相关表的CREATE TABLE语句以及EXPLAIN的结果 – Strawberry

对这里发生了什么的一种可能的解释是MySQL在之前选择进行排序它进行实际的连接。正如您在删除ORDER BY子句时在原始查询中看到的那样,加入本身不是性能问题。要解决这个问题的一种方法是来包装原始查询中的子查询,然后命令它:

SELECT * 
FROM 
(
    SELECT tablea.name, 
      tablea.views 
    FROM tablea 
    INNER JOIN tableb 
     ON tablea.id = tableb.id AND 
      tablea.balance > 0 
) t 
ORDER BY t.views ASC 
LIMIT 1 

如果一切正常,那么它很可能证实了我推测。在这种情况下,子查询强制MySQL仅对从实际子查询得到的记录进行排序。无论如何,你应该习惯于在这样的查询上运行EXPLAIN。我的猜测是,在加入原始查询时索引没有被使用/有效。

参考:Slow query when using ORDER BY

Given INDEX(x) 
ORDER BY x LIMIT 1 

将可以方便地使用索引和摘下的第一个项目

Given INDEX(x) 
WHERE ... 
ORDER BY x LIMIT 1 

也可以使用索引,希望一些早期行满意由WHERE。如果没有,那么它可能必须扫描整个表以找到一行!

Given INDEX(a, x) 
WHERE a = 12 
ORDER BY x LIMIT 1 

没问题 - 查找索引中的= 12;选择第一个项目。

Given INDEX(a, x) 
WHERE a > 12 
ORDER BY x LIMIT 1 

现在指数不太好。它将需要拾取所有行> 12,按x排序,然后交付一行。

一般来说,如果WHERE,和ORDER BY可以完全满足,则LIMIT n可以被优化。 (这里假定没有GROUP BY,或GROUP BYORDER BY相同。)

,其与一个表的。当你两个(或更多)表,它会变得更加混乱。有两个表格,优化器选择一个表格,找到它可以在那里,然后做一个嵌套循环加入到另一个表格。

通常(并非总是),WHERE子句(在一个表上)告诉优化器“接我”。如果这是与ORDER BY相同的表格,则上述讨论可能引入。

没有WHERE子句,优化程序通常从较小的表开始。 (注:本表的大小是根据行估计每一次可能不正确。)

你的第一个查询可能通过使用WHERE EXISTS (... tableb ...)代替JOIN tableb...来加快。优化器会将此视为值得优化的事物。

等,等,等

需要注意的是你的 “0.005秒” 是 “运气”。

如果您想更深入,提供SHOW CREATE TABLE(所以我们可以看到指数(ES)等),EXPLAIN SELECT(所以我们可以讨论一下优化决定),如果可能EXPLAIN FORMAT=JSON SELECT ...了解更多详情。另见my indexing cookbook