HIVE QL 杂记

  最近要处理用户访问日志,需要从HIVE中取数据,写了一些HIVE QL,有一点小感想,记录在此。

  1. 临时表

  在HIVE中进行多表连接时,可以给一些临时表命名,这样有助于理清查询语句之间的逻辑,格式为: 

#将从table表中取出的a,b列组成的临时表命名为t
(SELECT a,b FROM table) t

  在一些情况下,必须采用命名临时表的方法,比如我们在处理日志时,可能希望从日志的某个字段中抽取出某些有用的信息X,然后对X进行分组(GROUP BY X)。假设希望从URL中抽取出用户的ID,采用以下正则表达式regexp_extract(url,'uid=([0-9]+)',1),我们可能会写成以下形式:

#错误的HIVE QL,会报编译错误:找不到X列
SELECT regexp_extract(url,'uid=([0-9]?)',1) X FROM logs GROUP BY X

  这个时候HIVE会报语法错误,找不到X列。这种情况下,我们只能先抽取信息,将抽取出的信息组成的临时表进行命名,然后对这个表进行分组:

#首先将抽取信息组成的临时表命名为L,然后对临时表进行分组
SELECT L.X FROM(SELECT regexp_extract(url,'uid=([0-9]?)',1) FROM logs) L GROUP BY L.X

  2. 快速查询

  存储在HIVE中的表都是非常非常巨大的,所以加快查询速度非常重要。这方面的技巧非常多,在此只记录一下自己的一些经验。

  (1). 如果希望随机取出table表中的N条记录看一下,可以使用以下语句,很多情况下根本不会执行MAP/REDUCE语句,可能是直接从表元数据中取数据。

#快速从table表中取随机N条数据,可能不会触发M/R
SELECT * FROM table LIMIT N

  (2). 如果在创建表的时候根据某个列Y进行了分区(PARTITION),则在执行SELECT操作的时候,在WHERE子句中加入Y="xxx"可以显著地减少查询语句的执行时间。每个分区实际上是在HDFS当中表文件夹下面的一个子文件夹,在WHERE子句中使用分区列可以显著地减少搜索空间。详细信息见[2]。

  (3). 在执行多表连接时,尽量把小表放在左侧,一来左侧的表会被放入内存,这样将小表放在前面可以有效的防止内存泄露,而来首先连接小表会使得生成的临时表较小,有助于整个查询计划的加速,这点和SQL是一样的。

  3. 改写exist in

  HIVE QL不支持exist in,但是我们可以用其他语句进行改写:

#带exist in的SQL语句
SELECT t1.X FROM t1 WHERE t1.X EXIST IN (SELECT t2.X FROM t2)
#改写后的HIVE QL语句
SELECT t1.X FROM t1 LEFT JOIN t2 ON t1.X=t2.X WHERE t1.x!=NULL

  参考文献:

  [1]. 写好HIVE程序的五个提示

  [2]. Hive Tips

  [3]. HIVE0.5 中Partition简述

原文地址:https://www.cnblogs.com/kemaswill/p/2850410.html