字节面试手撕题分享

#数据人的面试交流地##数据人offer决赛圈怎么选#

​ 昨天也是被字节二面狠狠拷打了,问了一些Spark的技术细节和很多在上家公司的工作内容和项目架构,压力山大,不过感谢面试官捞我,算是通过了。

​ ok,现在分享一下当时出的一道手撕题:

存在表tablea(uid, cookie_id), 其中uid和cookie_id是联合主键 
存在表tableb(uid, order_id), 其中uid和order_id是联合主键
求(uid, cookie_id_cnt, order_id_cnt) 性能越快越好

当时首先想到是对两张表分别分组聚合再join

select
  COALESCE(a.uid, b.uid) AS uid,  -- 取存在的uid(处理仅在某一表存在的uid)
  COALESCE(a.cookie_id_cnt, 0) AS cookie_id_cnt,  -- 无数据则为0
  COALESCE(b.order_id_cnt, 0) AS order_id_cnt     -- 无数据则为0
from 
(
	select 
    	uid,
    	count(cookie_id) as cookie_id_cnt
    from tablea
    group by uid
) as aaa
full outer join
(
	select
    	uid,
    	count(order_id) as order_id_cnt
    from tableb
    group by uid
) as bbb

这是最简陋的方法,唯一能说的性能优化点几乎是先进行了聚合,这样后续对两张表的join时会减少数据的shuffle量。但是还是有shuffle存在。

将两张表的数据合并在一起,除了join之外还有其他的方式吗?

​ 这个问题其实在刷题网站上还是比较少见的,答案是有。join可以看成是横向合并,union系列可以看作是纵向合并。但是这又有一个问题,union系列操作对两张表纵向合并的时候,需要两张表的schema结构一致。而tablea和tableb的schema其实并不一致。这个时候就涉及到一个经典问题了 **是要时间还是要空间**,如果我们不管存储的开销,只为了计算更快的话,那我们就直接把两张表的schema变成一样的就行了嘛,而且在我们大数据场景下,存储的资源是较多的,所以以后做业务的时候要优先考虑到计算时间的问题。想清楚这些,就能得到一个不join的版本。

SELECT 
  distinct uid,
  sum(cookie_id_cnt) AS cookie_id_cnt,
  sum(order_id_cnt) AS order_id_cnt
FROM (
  -- 处理tablea:每条记录对应1个cookie_id
  SELECT 
    uid, 
    1 AS cookie_id_cnt, 
    0 AS order_id_cnt
  FROM tablea

  UNION ALL  

  SELECT 
    uid, 
    0 AS cookie_id_cnt,
    1 AS order_id_cnt
  FROM tableb
) AS combined
GROUP BY uid;

做手撕题的时候,最好把你的思路跟面试官讲清楚,

比如为什么不想用join?

​ 因为大表之间的join会进行很多shuffle操作,很浪费资源。

如果大表不得不join,你有什么好办法去优化性能呢?

​ 这时候你就要想到大表join大表的常用优化方案(分桶排序再join)。

为什么分桶排序再join能优化性能?

​ 这时候你要想到join为什么会导致大量的shuffle,原始是最开始读数据的时候是按照偏移量去读的,我们做表的join是,要把相同key的数据分区到同一个partition,涉及数据跨分区的重新分布就要用到shuffle,分桶之后就将数据先按照相同key分好,这样Spark读数据的时候,就能将按照事先通过桶分好的相同key的数据读到同一个分区,从而避免shuffle。

#数据人的面试交流地##数据人offer决赛圈怎么选#
全部评论

相关推荐

评论
2
5
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务