面试官:说说left join和left semi join 两者有什么区别?
Posted 洪生鹏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官:说说left join和left semi join 两者有什么区别?相关的知识,希望对你有一定的参考价值。
张工是一名程序员,主要是做java开发,有次到一家软件公司面试软件开发岗位,面试官问了他两个问题,其中有一个问题是这样的这样:
说说left join和left semi join 有什么区别?
对于left join 张工在平时编写sql用得比较多,但对于left semi join张工很少用到,所以说不出个所以然来了。
面试官见张工回答不上来,由于张工应聘的岗位对编写sql的水平要求较高,面试官就没有继续再问下去了,叫他先回去等通知。
太扎心了!一个问题没回答上来就被叫回去等通知了。
我们来看看hive 中的left join和left semi join有什么区别。
对于left join 我们平时经常用到,就不再具体阐述了,重点来关注下left semi join。
left semi join
可以这么理解,LEFT SEMI JOIN (左半连接)是 IN/EXISTS 子查询的一种更高效的实现。
示例
select
a.key,
a.value
from table_name_a a
where a.key in (select b.key from table_name_b b)
我们可以把这条sql可改写成
select
a.key,
a.value
from table_name_a a
left semi join table_name_b on(a.key=b.key)
-
left semi join特点
-
left semi join 的限制, join子句中右边的表只能在 on子句中设置过滤条件,在 where子句、select子句或其他地方过滤都是不可取的。
-
因为left semi join 是只传递表的 join key 给 map 阶段,所以left semi join 中最后 select 的结果只许出现左表。
-
因为 left semi join 是 in(keySet) 的关系,遇到右表重复记录,左表会跳过,而 join 则会一直遍历。这就导致右表有重复值的情况下 left semi join 只产生一条,join 会产生很多条记录,也会导致影响 left semi join 的性能更高。
上面的描述可能不太好理解,理解起来还是很吃力,我们来举个实例。
先建立两张表(学生表和分数表)并将这两张表进行初始化数据。
-
--学生表
create table test.tb_student (
id int comment 'id',
name string comment '姓名',
age int comment '年龄'
)
-- 初始化数据
INSERT INTO test.tb_student VALUES ('1', '张三', '7');
INSERT INTO test.tb_student VALUES ('2', '李四', '7');
INSERT INTO test.tb_student VALUES ('3', '王五', '7');
INSERT INTO test.tb_student VALUES ('4', '小爱', '7');
查询下test.tb_student表的数据
select * from test.tb_student
-
--分数表
create table test.course (
id int comment '学生id',
name string comment '课程名称',
score string comment '分数'
)
-- 初始化数据
INSERT INTO test.course VALUES ('1', '语文','90');
INSERT INTO test.course VALUES ('1', '数学','100');
INSERT INTO test.course VALUES ('1', '英语','90');
INSERT INTO test.course VALUES ('2', '语文','90');
INSERT INTO test.course VALUES ('2', '数学','90');
INSERT INTO test.course VALUES ('2', '英语','100');
INSERT INTO test.course VALUES ('3', '语文','100');
INSERT INTO test.course VALUES ('3', '数学','100');
INSERT INTO test.course VALUES ('3', '英语','99');
INSERT INTO test.course VALUES ('4', '语文','100');
INSERT INTO test.course VALUES ('4', '数学','100');
INSERT INTO test.course VALUES ('4', '英语','100');
查询下test.course表的数据
select * from test.course
通过上面的操作,我们已经成功创建了两张表并对其进行数据初始化。
下面我们来看看用left semi join和left join 操作后,查询出来的数据是怎样的?
-- left semi join
select * from test.tb_student a
left semi join test.course b on(a.id=b.id)
查询结果:
细心的你会发现,这不就是我们前面查询的test.tb_student表的数据吗?没错,确实是的,这是因为left semi join的select的结果中只允许出现t1(左表)表的字段
刚才的sql其实可以等价于
select * from test.tb_student a where a.id in (select id from test.course)
和
select * from test.tb_student a where exists (select 1 from test.course b where a.id=b.id)
他们执行的结果是一致的。
我们再来看看用left join查询出来会是什么样的结果。
--left join
select * from test.tb_student a
left join test.course b on a.id=b.id
查询结果:
从上面两者的执行结果我们可以清楚地看到left semi join 和 left join两者的区别了,这也应证了上面提到的关于left semi join的特点。
-
left semi join 是只传递表的 join key 给 map 阶段,因此left semi join 中最后 select 的结果只许出现左表。
-
left semi join 遇到右表重复记录,左表会跳过
面试时,要是面试官要是问起left join和left semi join 两者有什么区别这么细节的问题,比较友好地回答不妨参考这样的:
-
left semi join join子句中右边的表只能在 on子句中设置过滤条件
-
left semi join 中最后 select 的结果只许出现左表。
-
因为 left semi join 是 in(keySet) 的关系,遇到右表重复记录,左表会跳过,而 join 则会一直遍历。
要是能够回答出left semi join的特点,说明你完全有这方面的开发经验,相信能为这次面试加分。
总结:
-
对右表中重复key的处理方式差异:因为 left semi join 是 in(keySet) 的关系,遇到右表重复记录,左表会跳过,而 join on 则会一直遍历。
-
left semi join 中最后 select 的结果只许出现左表,因为右表只有 join key 参与关联计算了,而 join on 默认是整个关系模型都参与计算了。
由于笔者知识及水平有限,文中错漏之处在所难免,如有不足之处,欢迎交流。
-END-
微信公众号:洪生鹏
以上是关于面试官:说说left join和left semi join 两者有什么区别?的主要内容,如果未能解决你的问题,请参考以下文章
HiveSql&SparkSql —— 使用left semi join做inexists类型子查询优化