MapReduce模型中数据关联使用or语句导致计算效率低下
简介
MapReduce计算模型中,如果两个数据集的关联,并不是通过数据集的一个唯一键和另一个数据集的一个唯一键关联,那么会导致大量数据分发到一个节点计算,使其效率极其低下。
这里的MapReduce并不是仅仅是hive中的mapreduce模型,而是计算思想模型,比如spark、flink等,甚至更广阔的其余分布式计算框架等。
🌰
当一个hive中的sql有两个表table a,table b,存在两个关联关系a.a1=b.b1以及a.a2=b.b2。当使用如下sql:
select * from a, b where (a.a1=b.b1 or a.a2=b.b2);
如果查看hive执行计划,就可以看到最后reduce 只有一个,因为a表和b表的数据都分发到一个节点执行。
众所周知MapReduce模型是分布式计算模型,一般来说在shuffle节点会根据键值的哈希值分发到不同节点进入reduce阶段,如果两表关联式,这样就把两表的不重复的数据,分发到不同的节点执行,并且两表能关联上的数据肯定都在一个节点,不在一个节点的数据肯定关联不上。
再去看上述sql,当关联条件存在or时,如果只根据a1和b1的哈希值分发数据,那么当a2和b2可以关联时,很可能不在同一个节点上,也无法做关联,数据就会出问题;同理,只用a2和b2分发数据也会导致一样的问题;于是只能分配到一个节点执行。
现在修改一下sql
select * from a, b where
(a.a1=b.b1 or a.a1=b.b2);
此时a1字段能同时和b1以及b2关联,但是结果依然会相同,假设根据a1哈希值分发到了一个节点上,此时b1和b2和两个不同的哈希值,那么无论是通过b1还是b2哈希值分发数据,都可能导致另一个有可能关联上a1的字段没法关联上从而出错。
工作中经常遇到这种情况,解决方案也很简单,通过union all语法关联多条sql就完事了,需要的话再通过窗口函数去重。
后话
以上只是通过hive举例,有兴趣的朋友可以试试spark之类,因为无论是spark还是flink都是同一套分布式计算模型。
实际上问题很好发现,只不过一般写sql时候不容易注意到,有些分布式计算框架,比如我工作中常用的ignite,不像hive、spark、flink这样有这么高级的api来计算数据(比如sql语句),是采用十分底层的java代码来编写计算过程,此时就很容易发现上述问题。
posted on 2020-06-29 23:50 SaltFishYe 阅读(304) 评论(1) 编辑 收藏 举报