hive:join操作
hive的多表连接,都会转换成多个MR job,每一个MR job在hive中均称为Join阶段。按照join程序最后一个表应该尽量是大表,因为join前一阶段生成的数据会存在于Reducer 的buffer中,通过stream最后面的表,直接从Reducer中读取已经缓冲的中间数据结果,与后面的大表进行连接时,只需要从buffer中读取缓存的key,与大表中的指定key进行连接,速度更快,也避免内存缓冲区溢出。
- SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1);
另外,也可以通过一些hint信息来启发join操作,即指定那个表作为大表:
- SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
这样,就会先对表b和c进行join。
hive本身支持的子查询非常有限,Hive不支持where子句中的子查询,只允许子查询在from中出现
错误写法:
- insert into table branch_atmzc_sum
- Select XT_OP_TRL, SA_TX_DT,"取款-存款",b.cr_tx_amt- a.cr_tx_amt as cr_tx_amt from branch_atmzc a join branch_atmzc b on (a.XT_OP_TRL = b.XT_OP_TRL and a.SA_TX_DT = b.SA_TX_DT and a.tran_cd = 'ATM存款' and b.tran_cd = 'ATM取款'), counts from branch_atmzc
- group by XT_OP_TRL, SA_TX_DT,cr_tx_amt,counts;
正确写法:
- insert into table branch_atmzc_sum
- Select a.XT_OP_TRL, a.SA_TX_DT,"取款-存款",b.cr_tx_amt- a.cr_tx_amt ,b.counts+a.counts from branch_atmzc a join branch_atmzc b on (a.XT_OP_TRL = b.XT_OP_TRL and a.SA_TX_DT = b.SA_TX_DT and a.tran_cd = 'ATM存款' and b.tran_cd = 'ATM取款')
下面详细介绍各种连接方式的应用和效率
hive的join类型及其就是把MR 中的几种方式都封装实现了,其中代表性的有join on、 left semi join 是使用频率最高的。
join on 属于common join(shuffle join/reduce join),而left semi join 属于map join(broadcast join)的一一种变体。实现上原理有差异。
Common Join
最普通的join,即reduce side join,最没效率的一种方式,由一个mapreduce job完成。
实现原理:先对大表和小表分别进行map操作,在map shuffle的阶段每一个map output key 变成了table_name_tag_prefix + join_column_value , 但是在进行partition 的时候它仍然只使用join_column_value 进行hash.
每一个reduce 接受所有的map 传过来的split , 在reduce 的shuffle 阶段,它将map output key 前面的table_name_tag_prefix 给舍弃掉进行比较. 因为reduce 的个数可以由小表的大小进行决定,所以对于每一个节点的reduce 一定可以将小表的split 放入内存变成hashtable. 然后将大表的每一条记录进行一条一条的比较.
基于条件的 LEFT OUTER JOIN 优化
左连接时,左表中出现的join字段都保留,右表没有连接上的都为空。对于带where条件的join语句,如下:
- SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
- WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'
执行顺序是,首先完成两个表的join,然后再通过where条件过滤,这样在join时会输出大量结果,耗时。
进一步优化:把where条件放在on后,比如:
- SELECT a.val, b.val FROM a LEFT OUTER JOIN b
- ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07'
这样子,在join时,会对不满足条件的记录先预先过滤,效果更好。
左半连接(LEFT SEMI JOIN)
采用半连接的原因是:对于reduce side join,跨机器的传输量非常大,如果能够在map端过滤掉不需要进行join操作的数据,可以节省IO,提高效率。
实现原理:选取一个小表,假设是File1,将其参与join的可以抽取出来,保存到File3,一般都很好可以直接放到内存中。在map阶段,使用DistributedCache将File3复制到各个TaskTracker,然后可以将File2中不在File3中记录过滤掉,不参加join操作,然后剩下的reduce操作还是和reduce side join是一样的。
所以根据原理,更好理解:
(1)用了LEFT SEMI JOIN子句以后,右边的表在JOIN操作以外就不可见了,表b只能出现在on子句后面,不能出现在select和where语句中了,相当于右表只有join key参与关联计算了。
(2)对待右表中重复(key)时,因为left semi join是in(keySet)的关系,左表会直接跳过,而如果是join on 则会一直遍历。
左半连接类似IN/EXISTS的查询语句,对比如下:
- SQL:
- SELECT a.key, a.value FROM a WHERE a.key IN (SELECT b.key FROM b);
- Hive:
- SELECT a.key, a.val FROM a LEFT SEMI JOIN b ON (a.key = b.key)
注:b是其小表,b中只有join key 参与运算,不能出现在select 和where的筛选中。
关于子查询,这里提一下,Hive支持情况如下:
- 在0.12版本,只支持FROM子句中的子查询;
- 在0.13版本,也支持WHERE子句中的子查询。
join on 与 left semi on 比较输出特殊情况:
- Left semi join:
- select a.level2, a.name2,
- cast((a.alipay_fee) as double) as pay,
- cast(0 as double) as pay2
- from test1 a
- left semi join
- test2 b
- on (a.level2 = b.cat_id2
- and a.brand_id = b.brand_id
- and b.cat_id2 > 0
- and b.brand_id > 0
- and b.max_price = 0 )
- Join on:
- select a.level2, a.name2,
- cast((a.alipay_fee) as double) as pay,
- cast(0 as double) as pay 2
- from test1 a
- join test2 b
- on (a.level2 = b.cat_id2
- and a.brand_id = b.brand_id)
- where b.cat_id2 > 0
- and b.brand_id > 0
- and b.max_price = 0
陷阱:统计得到结果不一致,这是一个陷阱,因为子表中test2 b中存在重复的数据。当join on 时,a ,b表会关联到两条记录,在on上条件符合。
而当使用left semi join时,当A表中的记录,在B表上产生符合条件就返回,不会再继续查找B表的记录,所以即使有重复,也不会产生多条记录。
所以大多数情况下,两种方式是对等的,只有在有重复的记录时,要小心一点。
Map Side Join
MapJoin 即是 Map任务输出后,不需要将数据拷贝到Reducer节点,降低的数据在网络节点之间传输的开销。
多表连接,如果只有一个表比较大,其他表都很小,则JOIN操作会转换成一个只包含Map的Job,例如
- SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a JOIN b ON a.key = b.key;
所以对于表a的每一个map,都能够完全读取表b的数据。这里,表a和b不允许FULL OUTER JOIN、RIGHT OUTER JOIN。
BUCKET Map Side JOIN
我们先看两个表a和b的DDL,表a为:
- CREATE TABLE a(key INT, othera STRING)
- CLUSTERED BY(key) INTO 4 BUCKETS
- ROW FORMAT DELIMITED
- FIELDS TERMINATED BY '\001'
- COLLECTION ITEMS TERMINATED BY '\002'
- MAP KEYS TERMINATED BY '\003'
- STORED AS SEQUENCEFILE;
表b为:
- CREATE TABLE b(key INT, otherb STRING)
- CLUSTERED BY(key) INTO 32 BUCKETS
- ROW FORMAT DELIMITED
- FIELDS TERMINATED BY '\001'
- COLLECTION ITEMS TERMINATED BY '\002'
- MAP KEYS TERMINATED BY '\003'
- STORED AS SEQUENCEFILE;
- SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a JOIN b ON a.key = b.key
并且表a有4个BUCKET,表b有32个BUCKET,默认情况下,对于表a的每一个BUCKET,都会去获取表b中的每一个BUCKET来进行JOIN,这回造成一定的开销,因为只有表b中满足JOIN条件的BUCKET才会真正与表a的BUCKET进行连接。
这种默认行为可以进行优化,通过改变默认JOIN行为,只需要设置变量:
- set hive.optimize.bucketmapjoin = true
这样,JOIN的过程是,表a的BUCKET 1只会与表b中的BUCKET 1进行JOIN,而不再考虑表b中的其他BUCKET 2~32。
如果上述表具有相同的BUCKET,如都是32个,而且还是排序的,亦即,在表定义中在CLUSTERED BY(key)后面增加如下约束:
- SORTED BY(key)
则上述JOIN语句会执行一个Sort-Merge-Bucket (SMB) JOIN,同样需要设置如下参数来改变默认行为,优化JOIN时只遍历相关的BUCKET即可:
- sethive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
- set hive.optimize.bucketmapjoin = true
- set hive.optimize.bucketmapjoin.sortedmerge = true;
例子:
- SELECT
- t1.产品类型,
- COUNT(DISTINCT (IF(t2.用户ID IS NULL, NULL, t1.用户ID))) AS KEEP_UV
- FROM
- (
- SELECT
- 产品类型,
- 用户ID
- FROM 事实表
- WHERE (`DATE` >= 20140201 AND `DATE` <= 20140228)
- ) t1
- LEFT OUTER JOIN
- (
- SELECT
- 产品类型,
- 用户ID
- FROM 事实表
- WHERE (`DATE` >= 20140101 AND `DATE` <= 20140131)
- ) t2 ON (t1.产品类型 = t2.产品类型 AND t1.用户ID = t2.用户ID)
- GROUP BY t1.产品类型
本身表包含的字段信息多,时间跨度大。对于这种对于IN / EXISTS子查询(准确地说,这里是非相关子查询)有一种高效的实现,就是LEFT SEMI JOIN:
LEFT SEMI JOIN implements the uncorrelated IN/EXISTS subquery semantics in an efficient way.
left join
- SELECT
- 产品类型,
- COUNT(DISTINCT t1.用户ID) AS KEEP_UV
- FROM
- (
- SELECT
- 产品类型,
- 用户ID
- FROM 事实表
- WHERE (`DATE` >= 20140201 AND `DATE` <= 20140228)
- ) t1
- LEFT SEMI JOIN
- (
- SELECT
- 产品类型,
- 用户ID
- FROM 事实表
- WHERE (`DATE` >= 20140101 AND `DATE` <= 20140131)
- ) t2 ON (t1.产品类型 = t2.产品类型 AND t1.用户ID = t2.用户ID)
- GROUP BY 产品类型
hive:join操作的更多相关文章
- Hive中JOIN操作
1. 只支持相等JOIN. 2. 多表连接当使用不同的列进行JOIN时,会产生多个MR作业. 3. 最后的表的数据是从流中读取,而前面的会在内存中缓存,因此最好把最大的表放在最后. SELECT /* ...
- [Hive_add_5] Hive 的 join 操作
0. 说明 在 Hive 中进行 join 操作 1. 操作步骤 1.0 建表 在 hiveserver2 服务启动的前提下,在 Beeline客户端中输入以下命令 # 新建顾客表 create ta ...
- hive中的子查询改join操作(转)
这些子查询在oracle和mysql等数据库中都能执行,但是在hive中却不支持,但是我们可以把这些查询语句改为join操作: -- 1.子查询 select * from A a where a.u ...
- 使用MapReduce实现join操作
在关系型数据库中,要实现join操作是非常方便的,通过sql定义的join原语就可以实现.在hdfs存储的海量数据中,要实现join操作,可以通过HiveQL很方便地实现.不过HiveQL也是转化成 ...
- MapReduce 实现数据join操作
前段时间有一个业务需求,要在外网商品(TOPB2C)信息中加入 联营自营 识别的字段.但存在的一个问题是,商品信息 和 自营联营标示数据是 两份数据:商品信息较大,是存放在hbase中.他们之前唯一的 ...
- hive: join 遇到问题
在表连接时遇到一个问题: insert overwrite table BF_EVT_CRD_CRT_TRAD2 select BF_EVT_CRD_CRT_TRAD.*, jjkdjk.CUST_N ...
- Hive JOIN使用详解
转自http://shiyanjun.cn/archives/588.html Hive是基于Hadoop平台的,它提供了类似SQL一样的查询语言HQL.有了Hive,如果使用过SQL语言,并且不理解 ...
- 转载:几种 hive join 类型简介
作为数据分析中经常进行的join 操作,传统DBMS 数据库已经将各种算法优化到了极致,而对于hadoop 使用的mapreduce 所进行的join 操作,去年开始也是有各种不同的算法论文出现,讨论 ...
- hive join的三种优化方式
原网址:https://blog.csdn.net/liyaohhh/article/details/50697519 hive在实际的应用过程中,大部份分情况都会涉及到不同的表格的连接, 例如在进行 ...
随机推荐
- http常见状态码(转载)
常见HTTP状态码 常见HTTP状态码 200 OK 301 Moved Permanently 302 Found 304 Not Modified 307 Temporary Redirect 4 ...
- 【转】shell学习笔记(二) ——shell变量
在shell中有3种变量:系统变量,环境变量和用户变量,其中系统变量在对参数判断和命令返回值判断时会使用,环境变量主要是在程序运行时需要设置,用户变量在编程过程中使用量最多. 1 系统变量 变量名 ...
- 搭建yum仓库与定制rpm包
笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 当我们自动化部署集群的时候,想要快速的安装所有服务,搭建yum仓库与定制rpm包是我们首先要做的 原创作品,转载请 ...
- python的pika模块操作rabbitmq
上一篇博文rabbitmq的构架和原理,了解了rabbitmq的使用原理,接下来使用python的pika模块实现使用rabbitmq. 环境搭建 安装python,不会的请参考Linux安装配置py ...
- 关于dom4j解析xml
一:相关jar包 dom4j-1.6.1.jar 二:用例xml文件 三:解析 注:可能有的小白不知道如果获取节点,so,you can: for (Iterator<Element> i ...
- 再看Java基本类型
Java中的基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte.short.int.long.float.double. 数值类型又可以分为整数类型byte.short ...
- iterator和for of 循环
JavaScript 原有的表示"集合"的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set.这样就有了四种数据集合,用户还可以组合使用它们, ...
- 使用原生JS定位网页元素
约定:1.<meta name="viewport" content="width=device-width">这种标记简称"wdw&qu ...
- new day
Learning English is so long,but my english still is not good.I hope that one day I can speak english ...
- ubuntu下smb的配置
PS: 转自Ubuntu中文论坛 -------------------------------------------------------------------------------- ...