过滤表时加入表和存在有啥区别吗?

Posted

技术标签:

【中文标题】过滤表时加入表和存在有啥区别吗?【英文标题】:Is there any difference between joining tables and exists when filtering a table?过滤表时加入表和存在有什么区别吗? 【发布时间】:2019-03-04 22:09:06 【问题描述】:

我有两个表 A 和 B,想要获取 A 的子集,其键 k 也在 B 中。

一种选择是使用连接

select A.*
from A
join B on A.k = B.k

另一个是

select A.*
from A
where exists (select *, B.k from B where A.k = B.k)

如果 B 中的字段 k 是唯一的,我觉得它们是相同的。对于spark,子查询是否真的考虑了存在?

【问题讨论】:

【参考方案1】:

最简单最真实的方法是explain两个查询并比较他们的物理计划。

scala> println(spark.version)
2.4.0

scala> sql("select A.* from A join B on A.k = B.k").explain
== Physical Plan ==
*(2) Project [k#10L]
+- *(2) BroadcastHashJoin [k#10L], [k#6L], Inner, BuildRight
   :- *(2) Project [id#8L AS k#10L]
   :  +- *(2) Range (0, 10, step=1, splits=8)
   +- BroadcastExchange HashedRelationBroadcastMode(List(input[0, bigint, false]))
      +- *(1) Project [id#4L AS k#6L]
         +- *(1) Range (0, 10, step=1, splits=8)

scala> sql("""select * from a where exists (select *, B.k from B where A.k = B.k)""").explain
== Physical Plan ==
*(2) Project [id#8L AS k#10L]
+- *(2) BroadcastHashJoin [id#8L], [k#6L], LeftSemi, BuildRight
   :- *(2) Range (0, 10, step=1, splits=8)
   +- BroadcastExchange HashedRelationBroadcastMode(List(input[0, bigint, false]))
      +- *(1) Project [id#4L AS k#6L, id#4L AS k#6L]
         +- *(1) Range (0, 10, step=1, splits=8)

他们看起来很像,不是吗?

我觉得他们是一样的

如上所证明。

【讨论】:

没错,执行计划是比较性能和流程的最佳方式之一。如果在 SQl 上运行相同的东西会显示性能差异。因为在“存在”的情况下不会发生整个数据库遍历。 什么是“在 SQl 上” 我的意思是当一个人在 SQL 中运行这些时 “万一在 SQl 上运行相同的东西会显示性能差异。” 但这正是解释会告诉你的。如果有任何完整扫描,我们将有 Scan 节点(底部不是 Range)。

以上是关于过滤表时加入表和存在有啥区别吗?的主要内容,如果未能解决你的问题,请参考以下文章

sqlserver 的交叉连接和内部连接有啥区别吗?

MySQL中堆表和临时表的区别?

Netezza 中的表和外部表有啥区别?

关联表和常规表有啥区别?

文件系统过滤器驱动程序和文件系统微过滤器驱动程序有啥区别? (视窗)

SQL Server 中的临时表和表变量有啥区别?