Hive.LEFT SEMI JOIN子句

来源:互联网 发布:javascript代码规范 编辑:程序博客网 时间:2024/04/24 10:00

        公司的数据仓库和离线数据分析是建立在Hadoop + Hive基础上的,现在的工作主要是数据分析,自然也就跟HQL查询经常打交道了。刚来公司几乎完全不懂数据库知识,神马结构化查询语言也只是听说而已,不过,这没关系,实际工作一来,学习起来还是很快~~

        年前有一个同事叫帮忙查某个产品的月度留存UV这个数据,当时业务不熟,还去参照了一下别人是怎么定义留存用户这个指标的。。。然后根据自己的理解,用下面这种形式(其实刚开始的逻辑写得比这个还拙计,我不会到处乱说)的脚本逻辑去查:

SELECTt1.产品类型,COUNT(DISTINCT (IF(t2.用户ID IS NULL, NULL, t1.用户ID))) AS KEEP_UVFROM(SELECT产品类型,用户IDFROM 事实表WHERE (`DATE` >= 20140201 AND `DATE` <= 20140228)) t1LEFT OUTER JOIN(SELECT产品类型,用户IDFROM 事实表WHERE (`DATE` >= 20140101 AND `DATE` <= 20140131)) t2 ON (t1.产品类型 = t2.产品类型 AND t1.用户ID = t2.用户ID)GROUP BY t1.产品类型

        

       但是,这个事实表本身所包含的字段很多,信息量很大,加上时间跨度为2个月,当时就想会不会略慢,结果跑起来果然慢得很,Map或者Reduce的任务经常卡在某个百分点比较久时间。

       看着MapReduce像蜗牛一样行进着,我才忽然想到在官方Wiki上貌似看到过这种 IN / EXISTS子查询(准确地说,这里是非相关子查询)有一种高效的实现,就是LEFT SEMI JOIN:

       LEFT SEMI JOIN implements the uncorrelated IN/EXISTS subquery semantics in an efficient way.

       于是抱着试一试的心态,马上修改脚本,用下面的形式去跑:

SELECT产品类型,COUNT(DISTINCT t1.用户ID) AS KEEP_UVFROM(SELECT产品类型,用户IDFROM 事实表WHERE (`DATE` >= 20140201 AND `DATE` <= 20140228)) t1LEFT SEMI JOIN(SELECT产品类型,用户IDFROM 事实表WHERE (`DATE` >= 20140101 AND `DATE` <= 20140131)) t2 ON (t1.产品类型 = t2.产品类型 AND t1.用户ID = t2.用户ID)GROUP BY 产品类型


       果然,第2种脚本很快就出来结果了,而第1种脚本还在某个百分点艰难地挪步。。。

       值得注意的是,用了LEFT SEMI JOIN子句以后,右边的表在JOIN操作以外就不可见了,也就是说,右边的表只能在对应的ON子句中被引用。
       以上只是直观的感觉,从定性的层面感受到LEFT SEMI JOIN方式的性能真的是很不错,不晓得这样的效果除了来自Hive本身的官方高效实现外,与公司的生产环境有没有关系。。。
       怎么样,是不是想看看Hive这种特有的方式究竟为我们的查询带来了多大的时间效能改进?是不是也想看看它在源码里究竟是怎样的实现?行动起来吧。

1 0