我想知道使用 INNER JOIN 和相等运算符更快,或者当我尝试通过另一个表的列过滤表中的数据时使用 IN

Posted

技术标签:

【中文标题】我想知道使用 INNER JOIN 和相等运算符更快,或者当我尝试通过另一个表的列过滤表中的数据时使用 IN【英文标题】:I wonder using INNER JOIN and equality operator is faster or using IN when I try to filter data from a table by another table's column 【发布时间】:2019-12-19 07:19:06 【问题描述】:

当我尝试获取所有帐户时,这些帐户收到了来自foo@gmail.com 的消息。我想了解以下两个查询的性能。

SELECT *
FROM account
WHERE
    account_id in (
        SELECT distinct account_id
        FROM message mes
        WHERE mes.sender = 'foo@gmail.com'
    )

SELECT distinct account.*
FROM account acc
    INNER JOIN message mes
        ON mes.account_id = acc._id
WHERE
    mes.sender = 'foo@gmail.com'

谢谢!

【问题讨论】:

两个都运行,自己看看 race your horses 检查execution plan,如果你使用explain (analyze, buffers, format text),你也会看到时间安排 跑的太快了,不知道以后哪个更好 这是一个常见问题解答。在考虑发布之前,请始终在谷歌上搜索任何错误消息或您的问题/问题/目标的许多清晰、简洁和精确的措辞,有或没有您的特定字符串/名称和站点:***.com 和标签,并阅读许多答案。如果您发布问题,请使用一个短语作为标题。请参阅How to Ask 和投票箭头鼠标悬停文本。 【参考方案1】:

在这种情况下始终使用第一个查询。但是,不要在 IN句子查询中使用 DISTINCT。不要试图告诉 DBMS 如何执行IN。 (好吧,一个好的 DBMS 应该直接忽略 DISTINCT 并自己决定如何查找行。)

SELECT *
FROM account
WHERE account_id IN (SELECT account_id FROM message mes WHERE mes.sender = 'foo@gmail.com');

理想情况下,您应该在message (sender, account_id) 上有一个索引。消息表本身甚至不必被读取。在索引中查找发件人,然后获取所有匹配的帐户 ID。有了这些,您就可以阅读帐户,仅此而已。如果没有索引,这可能会慢得多,但仍然:读取消息表一次,获取不同的帐户 ID,然后读取帐户。没什么大不了的。

通过加入,您可以将所有消息与其帐户合并。这可能是一个相当大的中间结果,必须对其进行排序以获得不同的行。一个昂贵的操作。即使 DBMS 在连接和排序方面做得很好并且速度非常快,它仍然可以使用相同的方法来处理带有 IN 子句的简单查询。由 DBMS 制定一个好的计划,一个完美的 DBMS 会为两个查询提出完全相同的计划:-)

我的建议:仅当您对合并结果感兴趣时才加入。在你的情况下,你不是。您对符合某些条件的帐户感兴趣,因此请相应地编写查询。不要破坏您的查询,因为认为 DBMS 将使用另一种巧妙的方法。它甚至可能在当前 DBMS 版本中执行此操作,并在下一次更新时停止执行此操作。尽可能保持查询的可读性。如果您想要存在特定消息的帐户,请将WHEREEXISTSIN 一起使用。这就是应该编写 SQL 的方式。

【讨论】:

在我的学校,我的老师告诉我 JOIN 是一个代价高昂的查询,因此我对此表示怀疑。因为我的朋友通常使用第二个查询。我一直想深入了解我的疑问,非常感谢。【参考方案2】:

我不明白有些人不喜欢我的问题。在我的课堂上,我的老师教过我,当我们加入一个表时,这个动作非常复杂,因为结果表的大小可能会大两倍、三倍或更多。

现在我们假设一些数字:

X = account 表中的 1.000 条记录(1000 个用户)。 Y = 每个帐户拥有的 100 条消息。 Z = 每个用户拥有的 10 个朋友。 T = message 表中的 10.000 条消息。

在第一个查询中,当我们在 message 表的 10.000 条记录中搜索电子邮件 foo@gmail.com 时。然后我们将得到 Foo 发送给他们的 10 个 account_id。现在,当我们在表 user 中搜索时,我们将花费 1.000 时间来遍历每个帐户,并且我们将花费 10 时间来比较当前的 acocunt_id 和我们之前找到的列表 10 account_id。

根据数学,这个查询的复杂度是:10.000 + 1.000 * 10 T + X * Z

在第二个查询中,我们加入表,结果表期望的长度为10.000(因为account表和message表之间的关系是一对多,所以每条消息只属于一个帐户=>结果表的长度等于message表的长度),查询WHERE只需要1次比较。

根据数学,这个查询的复杂度是:10.000 T.

但我们没有看到结果表的长度可能会扩大两倍。而且我无法计算 JOIN 函数的复杂度。这就是我写这个问题的原因。

每个人都可以不喜欢我的问题。但我真的很想知道。

【讨论】:

以上是关于我想知道使用 INNER JOIN 和相等运算符更快,或者当我尝试通过另一个表的列过滤表中的数据时使用 IN的主要内容,如果未能解决你的问题,请参考以下文章

SQL中inner join,outer join和cross join的区别

SQL left joinright join和inner join的区别以及where的搭配使用

inner join和left join right join 的区别?

left join right join 和inner join之间的区别

join,left join,inner join的区别?

inner join/ left join/right join 之间的区别