MySQL继续加入有限的查询

时间:2016-05-04 17:53:04

标签: mysql join

我注意到,当服务器处于高负载时,我在一个相当大的表上执行的某个查询变得非常慢:

SELECT large.*, users.username 
FROM large
LEFT JOIN users ON large.user_id = users.id
ORDER BY large.abc 
LIMIT 30

large.user_idusers.id都已编入索引。)

因此,经过进一步检查,我意识到这是由于连接查询,因为删除连接查询使其变为即时。此外,重写查询同样快。

SELECT t.*, users.username 
FROM (
  SELECT * FROM large ORDER BY large.abc LIMIT 30
) as t 
LEFT JOIN users ON t.user_id = users.id

这是什么原因?是第一个在排序和限制之前加入所有行的查询,并且是解决此问题以使用第二个查询的最佳/唯一方法吗?

3 个答案:

答案 0 :(得分:0)

我可以提出建议并尝试一下,并根据我的SQL小提琴让我知道吗

CREATE INDEX large_abc_index ON large(abc);

第一个查询似乎更简单,并使用正确的键。 我用explain命令来解释这里的查询。 http://sqlfiddle.com/#!9/784faf/1

答案 1 :(得分:0)

在您的第一个查询中,您将large中的每一行加入其相应的用户,对large中所有现已加入的行进行排序,然后丢弃除30个之外的所有行。在第二个查询中,您需要排序large,丢弃除30之外的所有内容,然后将large子集加入users。因此,关键的区别在于连接了多少行。

我希望看到这些查询计划,但我怀疑第二个查询更快,因为临时表可读,与第一个查询相比,磁盘分页操作(它只有30行)要少得多(它有一个"大"行数)。

一般来说,子选择较慢,因为它们绕过了优化器的连接算法选择,并且必须完全依赖于解析查询,但在这种情况下,因为我们知道子选择只有30行,所以它似乎&# 39;比内置的连接优化器更好。

我怀疑如果您从子选择中删除LIMIT 30并将其放在外部查询上,您会发现性能低于您的第一个查询。但是,同样,EXPLAIN的输出对于解决这个谜团还有很长的路要走。

答案 2 :(得分:-2)

尝试根据此语法http://www.w3schools.com/sql/sql_join_left.asp

重新排序查询

加入应该在订购之前完成。

   SELECT large.*, users.username FROM large LEFT JOIN users ON large.user_id = users.id ORDER BY large.abc LIMIT 30