SQL常说用小表驱动大表,网上很多帖子也是说hive也是小表驱动大表。
但实际用expalin执行计划测的时候,Left Join大表写在前面时执行了MapJoin,小表写前面反而没采用MapJoin,为了确定确实是表大小的顺序原因,我更改了set hive.mapjoin.smalltable.filesize; 将其调小,即两张表都被认定为大表,则无论大表写前还是小表写前都无法进行mapJoin。
这是不是意味着:hive中为了采用MapJoin优化,在leftJoin时确实应该将大表写在前面,这和业务SQL数据库是相反了呢?
答:
并非如此,保留大表还是小表取决于业务逻辑,并不是语法上可以优化的。
大表会在Map阶段进行切割,分为多个MapTask, 而小表会通过缓存发往每一个MapTask进行Join操作,即Join操作在Map端即可完成,这就是MapJoin。
大表的切割会造成一个问题, MapJoin的局部性,就是在和小表Join时是很可能存在本应该匹配的数据在单个MapTask中没有Join上。如果采取LeftJoin,这意味着,MapTask的输出会产生多余数据(LeftKey, Null);如果保持大小表的书写顺序不变,采用RightJoin的方式,则不会存在这个问题,因为对于单个Task的大表数据而言,面对的是整体需要Join的小表数据。
总的来说,Hive中的mapJoin并不存在什么书写顺序,书写顺序是由业务决定的,只要开启了mapJoin,在成本评估合适的时候就会启用MapJoin。这具体表现在,InnerJoin不关心书写顺序;LeftJoin在小表在左侧,即小表完全保留的时候不会开启MapJoin,因为会产生很多空值连接的键值对,后续依旧要通过一个Reduce计算去除,且数据量很大不划算;RighJoin同理。 所谓的“小表驱动大表”和这里的MapJoin并不是一个概念,他指的是单服务器将小表加载内存,大表建立索引的过程;和这里的MapJoin减少网络传输,避免数据倾斜是不同的,设计理念就不同。