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

How to optimize MySQL "Order By Limit 1" in queries that join multiple tables?

所以我有这样的查询:

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 秒(大约)内达到 运行s。

更有趣的是:当我不将它加入 tableb 时,即:

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

通常在 0.005 秒内查询 运行s。

备注:

为什么第一个查询、删除 'order by' 时的第一个查询和第二个查询在性能上存在如此巨大的差异?

连接两个表时,有没有办法使排序更快?

关于这里发生的事情的一个可能的解释是 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 的习惯。我的猜测是在加入原始查询时索引不是 used/effective。

参考: Slow query when using ORDER BY

Given INDEX(x)
ORDER BY x LIMIT 1

将方便地使用索引并选择第一项

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

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

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

没问题 -- 在索引中查找 a=12;选择第一项。

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

现在索引不太好。它将需要选取所有 a>12 的行,按 x 排序,然后交付一行。

一般来说,如果WHEREORDER BY都可以完全满足,那么LIMIT n就可以优化了。 (假设没有 GROUP BY,或者 GROUP BYORDER BY 相同 。)

这是一个 table。当您 JOIN 两个(或更多)table 时,它会变得更加混乱。对于两个 table,优化器选择一个 table,找到它可以在那里找到的内容,然后对另一个 table.

执行嵌套循环连接

通常(不总是),一个 WHERE 子句(在一个 table 上)告诉优化器 "pick me"。如果 table 与 ORDER BY 相同,那么上述讨论可能会开始。

没有 WHERE 子句,优化器通常从较小的 table 开始。 (注意:table 大小基于行 估计 ,可能每次都不正确。)

使用 WHERE EXISTS ( ... tableb ... ) 而不是 JOIN tableb... 可能会加快您的第一个查询。优化器会将其视为值得优化的东西。

等等,等等,等等

请注意,您的“0.005 秒”是 "luck"。

如果您想深入挖掘,请提供 SHOW CREATE TABLE(以便我们可以看到索引等)、EXPLAIN SELECT(以便我们可以讨论优化器的决定)以及,如果可能 EXPLAIN FORMAT=JSON SELECT ... 了解更多详情。另见 my indexing cookbook .