我想知道使用 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 版本中执行此操作,并在下一次更新时停止执行此操作。尽可能保持查询的可读性。如果您想要存在特定消息的帐户,请将WHERE
与EXISTS
或IN
一起使用。这就是应该编写 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 的区别?