我想知道当我尝试通过另一个 table 的列从 table 过滤数据时,使用 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
虽然我正在尝试获取所有收到来自 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'
谢谢!
我不明白有些人不喜欢我的问题。在我的 class 中,我的老师曾教我,当我们加入一个 table 时,该操作非常复杂,因为结果 table 的大小可能是两倍、三倍或更多。
现在我们假设一些数字:
- X =
account
table. 中的 1.000 条记录(1000 个用户)
- Y = 每个帐户有 100 条消息。
- Z = 每个用户有 10 个朋友。
- T =
message
table. 中的 10.000 条消息
在第一个查询中,当我们在 message
table 的 10.000 条记录中搜索电子邮件 foo@gmail.com
时。然后我们将得到 Foo 发送给他们的 10 account_id。现在,当我们在 table 用户中搜索时,我们将花费 1.000 时间遍历每个帐户,我们将花费 10 时间将当前 acocunt_id 与我们之前找到的列表 10 account_id 进行比较。
According to mathematics, complexibility of this query is: 10.000 + 1.000 * 10 <=> T + X * Z
在第二个查询中,我们连接到 table 并且结果 table 期望的长度是 10.000(因为 account
table 和 [=11 之间的关系=] table 是一对多,所以每条消息只属于一个帐户 => 结果 table 的长度等于 message
table 的长度),并且query WHERE只需要1次比较。
According to mathematics, complexibility of this query is: 10.000 <=> T.
但是我们没有看到结果 table 的长度可能会扩展两倍大小。而且我无法计算 JOIN 函数的复杂度。这就是我写这个问题的原因。
大家可以不喜欢我的问题。但是我真的很想知道。
在这种情况下始终使用第一个查询。但是,不要在 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)
上有一个索引。消息 table 本身甚至不需要阅读。在索引中查找发件人,然后获取所有匹配的帐户 ID。有了它,您就可以阅读帐户,仅此而已。如果没有索引,这可能会慢得多,但仍然:阅读消息 table 一次,选择不同的帐户 ID,然后阅读帐户。没什么大不了的。
通过加入,您可以将所有邮件与其帐户合并。这可能是一个相当大的中间结果,必须对其进行排序以获得不同的行。一个昂贵的操作。即使 DBMS 非常适合连接和排序并且执行速度非常快,它仍然可以使用相同的方法来使用 IN
子句进行简单查询。由 DBMS 制定一个好的计划,一个完美的 DBMS 会为两个查询提出完全相同的计划:-)
我的建议:只有当你对加入的结果感兴趣时才加入。在你的情况下你不是。您对符合某些条件的帐户感兴趣,因此相应地编写查询。不要破坏您的查询,因为认为 DBMS 将使用另一种巧妙的方法。它甚至可能在当前的 DBMS 版本中执行此操作,并在下一次更新时停止执行此操作。尽可能保持查询的可读性。如果您想要某些消息存在的帐户,请使用 WHERE
和 EXISTS
或 IN
。 SQL应该是这样写的
虽然我正在尝试获取所有收到来自 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'
谢谢!
我不明白有些人不喜欢我的问题。在我的 class 中,我的老师曾教我,当我们加入一个 table 时,该操作非常复杂,因为结果 table 的大小可能是两倍、三倍或更多。
现在我们假设一些数字:
- X =
account
table. 中的 1.000 条记录(1000 个用户)
- Y = 每个帐户有 100 条消息。
- Z = 每个用户有 10 个朋友。
- T =
message
table. 中的 10.000 条消息
在第一个查询中,当我们在 message
table 的 10.000 条记录中搜索电子邮件 foo@gmail.com
时。然后我们将得到 Foo 发送给他们的 10 account_id。现在,当我们在 table 用户中搜索时,我们将花费 1.000 时间遍历每个帐户,我们将花费 10 时间将当前 acocunt_id 与我们之前找到的列表 10 account_id 进行比较。
According to mathematics, complexibility of this query is: 10.000 + 1.000 * 10 <=> T + X * Z
在第二个查询中,我们连接到 table 并且结果 table 期望的长度是 10.000(因为 account
table 和 [=11 之间的关系=] table 是一对多,所以每条消息只属于一个帐户 => 结果 table 的长度等于 message
table 的长度),并且query WHERE只需要1次比较。
According to mathematics, complexibility of this query is: 10.000 <=> T.
但是我们没有看到结果 table 的长度可能会扩展两倍大小。而且我无法计算 JOIN 函数的复杂度。这就是我写这个问题的原因。
大家可以不喜欢我的问题。但是我真的很想知道。
在这种情况下始终使用第一个查询。但是,不要在 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)
上有一个索引。消息 table 本身甚至不需要阅读。在索引中查找发件人,然后获取所有匹配的帐户 ID。有了它,您就可以阅读帐户,仅此而已。如果没有索引,这可能会慢得多,但仍然:阅读消息 table 一次,选择不同的帐户 ID,然后阅读帐户。没什么大不了的。
通过加入,您可以将所有邮件与其帐户合并。这可能是一个相当大的中间结果,必须对其进行排序以获得不同的行。一个昂贵的操作。即使 DBMS 非常适合连接和排序并且执行速度非常快,它仍然可以使用相同的方法来使用 IN
子句进行简单查询。由 DBMS 制定一个好的计划,一个完美的 DBMS 会为两个查询提出完全相同的计划:-)
我的建议:只有当你对加入的结果感兴趣时才加入。在你的情况下你不是。您对符合某些条件的帐户感兴趣,因此相应地编写查询。不要破坏您的查询,因为认为 DBMS 将使用另一种巧妙的方法。它甚至可能在当前的 DBMS 版本中执行此操作,并在下一次更新时停止执行此操作。尽可能保持查询的可读性。如果您想要某些消息存在的帐户,请使用 WHERE
和 EXISTS
或 IN
。 SQL应该是这样写的