一、HIVE SQL 语法
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM tablename
[WHERE where_condition] --where条件语句
[GROUP BY col_list] --group by 分组语句
[ORDER BY col_list] --order by 排序语句
[CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY col_list] ]
[LIMIT number]
大家都知道hive底层跑的是mapreduce程序,在执行hql语句时,mapreduce会解析hql产生执行逻辑,生成结果。
MapReduce引擎执行计划
Map阶段:
1、执行from加载,进行表的查找与加载。
2、执行where过滤,进行条件过滤与筛选。
3、执行select查询,进行输出项的筛选。
4、执行group by分组,描述了分组后需要计算的函数。
5、map端文件合并,map端本地溢出写文件的合并操作,每个map最终形成一个临时文件。然后按列映射到对应的Reduce阶段:
Reduce阶段:
1、group by:对map端发送过来的数据进行分组并进行计算。
2、select:最后过滤列用于输出结果。
3、limit排序后进行结果输出到HDFS文件。
注意,以上顺序不是绝对的,会根据语句的不同,有所调整。
可以通过执行计划查看大概顺序
explain sql 语句
如:explain select * from tablename 即可查看执行计划
二、Hive Join
Hive只支持等连接、外连接。Hive不支持非相等的Join条件,不过我们可以通过其他方式实现,如left outer join,因为它很难在map/reduce job实现这样的条件。建表对Join操作进行试验,建表语句和数据如下:
//我们创建三个表用来测试
CREATE TABLE testA(
id INT COMMENT 'id',
name STRING COMMENT '姓名',
age INT COMMENT '年龄'
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
CREATE TABLE testB(
id INT COMMENT 'id',
name STRING COMMENT '姓名',
age INT COMMENT '年龄'
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
CREATE TABLE testC(
id INT COMMENT 'id',
name STRING COMMENT '姓名',
age INT COMMENT '年龄'
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
INSERT INTO TABLE testA VALUES (1,"唐三",20);
INSERT INTO TABLE testA VALUES (2,"石昊",21);
INSERT INTO TABLE testA VALUES (5,"林动",18);
INSERT INTO TABLE testA VALUES (6,"萧炎",17);
INSERT INTO TABLE testB VALUES (1,"周元",19);
INSERT INTO TABLE testB VALUES (3,"李明",22);
INSERT INTO TABLE testB VALUES (4,"叶修",23);
INSERT INTO TABLE testB VALUES (5,"吴邪",17);
INSERT INTO TABLE testC VALUES (1,"孙无",24);
INSERT INTO TABLE testC VALUES (2,"沙沙",25);
INSERT INTO TABLE testC VALUES (6,"唐四",21);
INSERT INTO TABLE testC VALUES (7,"叶凡",20);
2.1、两表的inner join
SELECT
a.id id,
a.name aname,
a.age aage,
--b.id bid,
b.name bname,
b.age bage
FROM
testa a
INNER JOIN
testb b
ON a.id = b.id
结果:
1 唐三 20 周元 19
5 林动 18 吴邪 17
2.2、外连接:left join 和 right join
--left join
SELECT
a.id id,
a.name aname,
a.age aage,
b.name bname,
b.age bage
FROM
testa a
LEFT JOIN
testb b
ON a.id = b.id
结果:
1 唐三 20 周元 19
2 石昊 21 NULL NULL
5 林动 18 吴邪 17
6 萧炎 17 NULL NULL
--right join
SELECT
a.id id,
a.name aname,
a.age aage,
b.name bname,
b.age bage
FROM
testa a
RIGHT JOIN
testb b
ON a.id = b.id
结果:
1 唐三 20 周元 19
NULL NULL NULL 李明 22
NULL NULL NULL 叶修 23
5 林动 18 吴邪 17
2.3、 实现非等值连接
查询testa有,testb没有,用 left join + is null
查询testa没有,testb有,用 right join + is null
--查询testa有,testb没有
SELECT
a.id aid,
a.name aname,
a.age aage,
b.id bid,
b.name bname,
b.age bage
FROM
testa a
LEFT JOIN
testb b
ON
a.id = b.id
WHERE
b.id IS NULL
结果:
2 石昊 21 NULL NULL NULL
6 萧炎 17 NULL NULL NULL
--查询testa没有,testb有。同理,如上把b.id改为a.id即可。
注意下面的Sql和上面的Sql结果是不一样的:
SELECT
a.id aid,
a.name aname,
a.age aage,
b.id bid,
b.name bname,
b.age bage
FROM
testa a
LEFT JOIN
testb b
ON
a.id = b.id
AND
b.id IS NULL
结果:
1 唐三 20 NULL NULL NULL
2 石昊 21 NULL NULL NULL
5 林动 18 NULL NULL NULL
6 萧炎 17 NULL NULL NULL
2.4、多表join
--笛卡尔积的SQL
select
a.id id,
a.name aname,
a.age aage,
b.name bname,
b.age bage
from testa a
inner join testb b;
简单应用:使用join计算新增用户
--计算新增用户
select count(1) from
(select uid from user_table where dt='20200506' group by uid) a
right join
(select uid from user_table where dt='20200507' group by uid) b
on b.uid=a.uid
where a.uid is null;
2.5、使用join时要避免的查询操作
--笛卡尔积的SQL
select
a.id id,
a.name aname,
a.age aage,
b.name bname,
b.age bage
from testa a
inner join testb b;
设置 set hive.mapred.mode=strict 这个参数,可以限制以下情况:
1)限制执行可能形成笛卡尔积的SQL;
2)partition表使用时不加分区;
3)order by全局排序的时候不加limit的情况;
取消限制:set hive.mapred.mode=nonstrict
2.6、full outer join
full outer join意思是包括两个表join的结果。左边有、右边NULL,右边有、左边NULL。其结果等价于left join union right join
select
a.id id,
a.name aname,
a.age aage,
b.name bname,
b.age bage
from testa a
full outer join testb b
on a.id = b.id
结果:
1 唐三 20 周元 19
6 萧炎 17 NULL NULL
NULL NULL NULL 李明 22
5 林动 18 吴邪 17
NULL NULL NULL 叶修 23
2 石昊 21 NULL NULL
使用union 实现 full outer join效果
select
a.id id,
a.name aname,
a.age aage,
b.name bname,
b.age bage
from testa a
LEFT JOIN testb b
on a.id = b.id
UNION
select
a.id id,
a.name aname,
a.age aage,
b.name bname,
b.age bage
from testa a
RIGHT JOIN testb b
on a.id = b.id
2.7、map端的join操作
当大表 join 小表时,小表没有运行Map,两个表连在一起也没有用Reduce,直接跳过,将小表数据刷入内存,默认是自动mapjoin。
hive 默认是开启 MapJoin/*+ MAPJOIN(c) */
//将小表刷入内存中,默认是true
set hive.auto.convert.join=true
set hive.ignore.mapjoin.hint=true
//刷入内存表的大小(字节),根据自己的数据集加大
set hive.mapjoin.smalltable.filesize=2000000
不开启MapJoin,可以按照如下设置
set hive.auto.convert.join=false;
set hive.ignore.mapjoin.hint=false;
在设置成false 或 true时,可以手动的 /*+ MAPJOIN(c) **/
select /*+ MAPJOIN(c) */ * from user_table_a a
inner join user_table_b b
on a.id=b.id
where a.dt='20200507'
注意:map join 类似于 MapReduce中的semijoin。
当把set hive.auto.convert.join设置成false时,可以手动的加 /*+ MAPJOIN(c) ***/外连接不允许用mapjoin ,内连接可以用mapjoin / *+ MAPJOIN(c) */把c放到内存。