MySQL:LEFT JOIN和ORDER BY的组合很慢

时间:2016-04-16 06:42:23

标签: mysql join left-join query-performance

有两个表:posts(约5,000,000行)和relations(约8,000行)。

posts列:

-------------------------------------------------
|  id  |  source_id  |  content  |  date (int)  |
-------------------------------------------------

relations列:

---------------------------
|  source_id  |  user_id  |
---------------------------

我为posts获取10个与特定用户相关的最近行编写了一个MySQL查询:

SELECT      p.id, p.content
FROM        posts AS p
LEFT JOIN   relations AS r
ON          r.source_id = p.source_id
WHERE       r.user_id = 1
ORDER BY    p.date DESC
LIMIT       10

然而,执行它需要约30秒。

relations(source_id, user_id)以及(user_id)(source_id)(date) (date, source_id)处的posts已有索引

EXPLAIN结果:

EXPLAIN results

如何优化查询?

5 个答案:

答案 0 :(得分:1)

你可以在posts表的日期列上放一个索引,我相信这有助于订单的速度。

您还可以在使用其他where语句进行排序之前尝试减少结果数量。例如,如果你知道今天可能有10条记录带有正确的user_id,你可以将日期限制在今天(或者根据你的实际数据将N天限制在后面)。

答案 1 :(得分:1)

您的WHERE子句将外部联接呈现为内部联接(因为在外部联接的伪记录中,user_id将始终为null,从不为1)。

如果你真的希望这是一个外部联接,那么它是完全多余的,因为{{1>}中的每个记录在posts当然有或没有匹配。您的查询将是

relations

如果您不希望它真的是外部联接,但想要} {/ 1}}中的匹配,那么我们在谈论表格中的存在,{{1}因此:或select id, content from posts order by "date" desc limit 10; 条款:

relations

EXISTS上应该有一个索引 - 按此顺序,我们可以先选择IN 1,然后获取所有需要select id, content from posts where source_id in ( select source_id from relations where user_id = 1 ) order by "date" desc limit 10; 的数组,然后我们会查找。

当然,您还需要一个relations(user_id, source_id)的索引,因为user_id是一个ID。您甚至可以使用复合索引source_id来加快速度,因此不必再读取表本身 - 所需的所有信息都已在索引中。

更新:以下是相关的posts(source_id)查询:

source_id

答案 2 :(得分:0)

试试这个

    SELECT p.id, p.content FROM posts AS p
    WHERE p.source_id IN (SELECT source_id FROM relations WHERE user_id = 1)
    ORDER BY  p.date DESC
    LIMIT       10

答案 3 :(得分:0)

我会考虑以下几点: -

首先,您只需要与用户相关的帖子中的10个最新行。所以,INNER JOIN应该做得很好。

SELECT      p.id, p.content
FROM        posts AS p
JOIN        relations AS r
ON          r.source_id = p.source_id
WHERE       r.user_id = 1
ORDER BY    p.date DESC
LIMIT       10

如果要获取没有LEFT JOIN映射的记录,则需要relations。因此,执行LEFT JOIN会导致左表的全表扫描,根据您的信息,包含约5,000,000行。这可能是您查询的根本原因。

要进一步优化,请考虑将WHERE子句移到ON子句中。

SELECT      p.id, p.content
FROM        posts AS p
JOIN        relations AS r
ON          (r.source_id = p.source_id AND r.user_id = 1)
ORDER BY    p.date DESC
LIMIT       10

答案 4 :(得分:0)

我会尝试使用关系的综合索引:

INDEX source_user (user_id,source_id)

并将查询更改为:

SELECT      p.id, p.content
FROM        posts AS p
INNER JOIN   relations AS r 
ON ( r.user_id = 1 AND r.source_id = p.source_id )
ORDER BY    p.date DESC
LIMIT       10