1,inner join
内连接(inner join)中,只有进行连接的两个表中都存在与连接标准相匹配的数据才会被保留下来。列如,如下我们有两张表员工表(employee)和办公表(office)连接条件是oid字段,内容必须相等,我们也称oid字段这个查询语句中连接关键字。
提供两个表的数据:
我们这里提供两种写法(第一种中的inner join 可以简写 join) 1,select a.*,b.* from employee a inner join office b on a.oid = b.oid where a.salary>=5000; 2,select a.*,b.* from employee a ,office b where a.oid = b.oid and a.salary>=5000; 结果: a.eid | a.name | a.salary | a.oid | b.oid | b.name | +--------+---------+-----------+--------+--------+---------+ | 2 | Alice | 5000 | 2 | 2 | SH | | 3 | Marry | 6000 | 2 | 2 | SH 我们可以看到员工表oid是4的工资大于5000却没有查出来,这就是内连接的作用,连接关键字字段的数据要一一对应不然他会显示你的数据
2,left(right) outer join
左连接通过关键字 left outer 进行标识;右连接通过关键字 right outer 进行标识;
select a.*,b.* from employee a left(right) outer join office b on a.oid=b.oid where a.salary>=5000; (左连接)结果: +--------+---------+-----------+--------+--------+---------+ | a.eid | a.name | a.salary | a.oid | b.oid | b.name | +--------+---------+-----------+--------+--------+---------+ | 2 | Alice | 5000 | 2 | 2 | SH | | 3 | Marry | 6000 | 2 | 2 | SH | | 4 | zxz | 10000 | 3 | NULL | NULL | 以上我们可以看出左连接是把左表符合where子句的所有记录将会被返回,如果对应的表没有该数据则会使用null代替,右连接则相反,在这里就不举例说明了,一般会左连接就行了,因为他们的左右没什么区别。
注意:where语句在连接操作执行后才会执行,因此where语句应该只用于过滤那些非null值得列值,同时on语句中的分区过 滤条件在外链接(outer join)是没用的,不过在inner join中是有效的。如果我们想在连接之前避免使用on条件和where条件来过滤数据的话的情况下我们可以使用嵌套查询:
select a.*,b.* from (select * from employee where eid <=3) a (inner join,left outer join,right outer join取一个使用即可) office b on a.oid=b.oid;
3,full outer join
完全外连接(full outer) 将会返回所有表中符合where语句条件的所有记录,如果任一表的指定字段没有符合条件值得话,那么久使用null值代替代。
如果我们前面将前面的查询改成一个完全外链接查询的话,事实上获得结果和之前的一样
select a.*,b.* from employee a full outer join office b on a.oid=b.oid; 结果: +--------+---------+-----------+--------+--------+---------+ | a.eid | a.name | a.salary | a.oid | b.oid | b.name | +--------+---------+-----------+--------+--------+---------+ | 1 | Jack | 3000 | 1 | 1 | BJ | | 3 | Marry | 6000 | 2 | 2 | SH | | 2 | Alice | 5000 | 2 | 2 | SH | | 4 | zxz | 10000 | 3 | NULL | NULL | | NULL | NULL | NULL | NULL | 4 | WC | 因为要给你们看效果就没加条件,我们会发现他把所有的数据都连接在一块了
4,left smi-join
左半开连接(left semi-join)会返回左边表的记录,前提是其记录对于右边表满足on语句中的判断条件,对于常见的内连接(inner join)来说,这是一个特殊的、优化了的情况,大多数的SQL方言会通过in ...exists结构来处理这种情况。但hive不支持,我们就可以使用left semi-join 方式:
select a.* from employee a left semi join office b on a.oid=b.oid and b.oid=2; 结果: +--------+---------+-----------+--------+ | a.eid | a.name | a.salary | a.oid | +--------+---------+-----------+--------+ | 2 | Alice | 5000 | 2 | | 3 | Marry | 6000 | 2 | 结果很明显他返回的是左表的条件数据,而且会比in函数查询的快
5,笛卡尔积 join
笛卡尔积是一种连接,表示左边表的行数乘以右边表的行数等于笛卡尔积结果集的大小。也就说如果左表表有4行数据,右边有3行数据,那么产生的数据将是4*3行数据。因此我们使用笛卡尔积会产生大量数据,他与其他类型不同,笛卡尔积不是并行执行的,而且使用mapreduce计算框架的话,任何方式都无法进行优化。如果使用看错误的连接(join)语法可能会导致产生一个执行时间长,运行缓慢的笛卡尔积。
在hive中,这个查询在应用where语句中的谓词条件前会先进性笛卡尔积计算,这个过程会消耗很大,如果设置属性 hive.mapred.mode 值为strict的话,hive会执行笛卡尔积查询,所有我们如果没有太大的需求尽量不要使用
set hive.mapred.mode=unstrict; //设置为非严格模式 select a.*,b.* from employee a CROSS join office b where a.oid=b.oid ; 结果: +---------------+----------------+------------------+---------------+-------------+--------------+ | employee.eid | employee.name | employee.salary | employee.oid | office.oid | office.name | +---------------+----------------+------------------+---------------+-------------+--------------+ | 2 | Alice | 5000 | 2 | 1 | BJ | | 2 | Alice | 5000 | 2 | 2 | SH | | 2 | Alice | 5000 | 2 | 4 | WC | | 3 | Marry | 6000 | 2 | 1 | BJ | | 3 | Marry | 6000 | 2 | 2 | SH | | 3 | Marry | 6000 | 2 | 4 | WC | | 1 | Jack | 3000 | 1 | 1 | BJ | | 1 | Jack | 3000 | 1 | 2 | SH | | 1 | Jack | 3000 | 1 | 4 | WC | | 4 | zxz | 10000 | 3 | 1 | BJ | | 4 | zxz | 10000 | 3 | 2 | SH | | 4 | zxz | 10000 | 3 | 4 | WC |
笛卡尔积在一些情况下还是有用的,例如:假如有一个表示用户偏好,另一个表表示新闻文章,同时有一个算法会推测出用户可能会喜欢读那些文章,这个时候就需要笛卡尔积生成所有用户和所有网页的对应关系集合。
6, join优化
在之前的例子中,每个on子句中都使用到a.oid=b.oid作为join的连接键。在这种情况下,hive通过一个优化可以在同一个mapreduce job中连接3张表,同样,如果a.oid也用于on子句的话,那么也会应用到这个优化
提示:当对3个或者更多个表进行join连接时,如果每个on子句使用相同的连接键的话,那么只会产生一个 mapreduce job
hive 同时假定查询中最后一个表是最大的那个表,在对每行记录进行连接操作时,他会尝试将其他表缓存起来,然后扫描最后那个表进行计算,因此,用户要保证连续查询中的表的大小要从左到右依次增加的,对于大数据集会是很大的提速。
7, map-side join
在之前的例子中,每个on子句中都使用到a.oid=b.oid作为join的连接键。在这种情况下,hive通过一个优化可以在同一个mapreduce job中连接3张表,同样,如果a.oid也用于on子句的话,那么也会应用到这个优化
提示:当对3个或者更多个表进行join连接时,如果每个on子句使用相同的连接键的话,那么只会产生一个 mapreduce job
如果所有表中只有一张表是小表,那么可以在最大的表通过mapper的时候将小表完全放到内存中,hive可以在map端执行连接过程(称为 map-side join),这是因为hive可以和内存中的小麦表进行逐一匹配,从而省略掉常规连接操作需要的reduce过程。即使对于很小的数据集,这个优化也和明显地要快与常规的连接操作,其不仅减少了reduce过程,而且有时还可以同时减少map过程的执行过程
1,select /*+ mapjoin(a) */ a.*,b.* from customers a left outer join orders b on a.id = b.cid ; 弃用了
2,我们,可以设置属性: hive.auto.convert.join=true,
还可以指定小表的大小默认: hive.majoin.smalltable,filesize=25000000(25M);
这种优化不支持:右外连接和全外链接,如果我们使用桶表来使用这种优化将会带来不小的作用;
本次介绍来自,hive编程指南.pdf 详情请下载观看!