hive从查询中获取数据插入到表或动态分区

Hive的insert语句可以从查询语句中获取数据,并同时将数据Load到目标表中。如今假定有一个已有数据的表staged_employees(雇员信息全量表),所属国家cnty和所属州st是该表的两个属性,咱们作个试验将该表中的数据查询出来插入到另外一个表employees中。node

INSERT OVERWRITE TABLE employees
PARTITION (country = '中国', state = '北京')
SELECT * FROM staged_employees se
WHERE se.cnty = '中国' AND se.st = '北京';

因为使用了OVERWRITE关键字,目标表中原来相同partition中的全部数据被覆盖,若是目标表中没有partition,则整个表会被覆盖。sql

若是把OVERWRITE关键字删掉,或者替换成INTO,则hive会追加而不是替代原分区或原表中的数据,这个特性在Hive v0.8.0以后才支持。app

当数据已经存在于hdfs上但不是咱们想要的格式的时候,当进行的计算须要分好多步骤有必要存储中间数据的时候,或者原数据没有分区、有不少无效列须要过滤的时候,可使用insert..select句型来完成这一转换过程。oop

因为一个国家有不少个省份,若是想根据(国家country,地区partition)两个维度对数据进行分区的话,这条SQL语句的执行个数应该等于地区的数目,好比中国有23个省就要对该SQL语句执行23次。所以hive对这个SQL语句进行了改造,只须要扫描一次原表就能够生成不一样的输出(多路输出)。好比下面的SQL语句扫描了一次原始数据表,可是同时生成了3个省份的结果数据:spa

FROM staged_employees se
INSERT OVERWRITE TABLE employees
	PARTITION (country = '中国', state = '河北省')	
	SELECT * WHERE se.cnty = '中国' AND se.st = '河北省'
INSERT OVERWRITE TABLE employees
	PARTITION (country = '中国', state = '陕西省')	
	SELECT * WHERE se.cnty = '中国' AND se.st = '陕西省'
INSERT OVERWRITE TABLE employees
	PARTITION (country = '中国', state = '河南省')	
	SELECT * WHERE se.cnty = 'US' AND se.st = '河南省';

经过缩进能够很清楚的看到,咱们扫描了一次staged_employees表可是执行了3次不一样的insert语句,这条大SQL语句是这么执行的:先经过from staged_employees表获取一条记录,而后执行每个select子句,若是select子句验证经过则执行相应的insert语句。注意这里的三条select子句是彻底独立执行的,并非if .. then .. else的关系,这就意味着这3条select子句在某种状况下可能同时经过where检测。设计

经过这种结构,原始表的数据能被拆分到目标表的不一样partition中去。code

若是原表的一条记录知足于其中一个给定的select .. where .. 子句,则该记录将被写到目标表的固定分区中。其实更进一步,每条Insert语句能将数据写到不一样的数据表中,无论这个表是否分区都同样。orm

因而,就像一个过滤器同样,原表的一些数据被写到了不少输出地址,而剩下的数据会被丢弃。hadoop

固然,你也能够混用Insert overwrite和insert into两种不一样的方法写出数据。ci

向动态分区插入数据

可是问题仍是没有解决,中国有23个省,那么咱们就须要写23个insert into .. select ..where子句,这很是不现实。因而hive的一种叫作动态分区的特性就出现了,它可以根据select出来的参数自动推断将数据插入到那个分区中去。本文上面的两种SQL语句设定分区的方式都叫作静态分区插入。

将上一个SQL语句进行改动,会获得如下简洁的新SQL语句:

INSERT OVERWRITE TABLE employees
PARTITION (country, state)
SELECT ..., se.cnty, se.st
FROM staged_employees se;

hive先获取select的最后两个位置的se.cnty和se.st参数值,而后将这两个值填写到Insert语句partition中的两个country和state变量中,即动态分区是经过位置来对应分区值的。原始表select出来的值和输出partition的值的关系仅仅是经过位置来肯定的,和名字并无关系,好比这里se.cnty和county的名称彻底没有关系。

上面的这条SQL语句是对两个分区同时进行了动态设定,若是staged_employees表中有100个国家,每一个国家有100个地区,那么该SQL语句自动对每一个国家和地区创建相应的partition并插入数据,若是用手写的话不现实。

只要位置正确,你能够混用动态分区和静态分区值设定,好比下面这个例子,你能够静态指定一个country值,可是state值采用动态的方法设定:

INSERT OVERWRITE TABLE employees
PARTITION (country = 'US', state)
SELECT ..., se.cnty, se.stFROM staged_employees se
WHERE se.cnty = 'US';

使用hive动态分区的参数设定

动态分区功能默认是关闭的,而当它是打开状态时,默认会工做在“strict”模式下,这种模式下要求至少指定一个静态分区的值。这样作是为了防止设计了大量partition的糟糕状况,举个例子你使用时间戳来进行分区,居然每一秒钟都产生一个分区!还有其余的一些属性设定用来限制相似的状况出现,以下表所示:

名称 默认值 描述
hive.exec.dynamic.partition false 设置为true用于打开动态分区功能
hive.exec.dynamic.partition.mode strict 设置为nonstrict可以让全部的分区都动态被设定,不然的话至少须要指定一个分区值
hive.exec.max.dynamic.partitions.pernode 100 能被每一个mapper或者reducer建立的最大动态分区的数目,若是一个mappre或者reducer试图建立多余这个值的动态分区数目,会引起错误
hive.exec.max.dynamic.partitions +1000 被一条带有动态分区的SQL语句所能建立的动态分区总量,若是超出限制会报出错误
hive.exec.max.created.files 100000 全局能被建立文件数目的最大值,专门有一个hadoop计数器来跟踪该值,若是超出会报错

举个例子,使用全动态分区的SQL语句序列以下所示,须要先设定一些必要的参数才能够:

set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
set hive.exec.max.dynamic.partitions.pernode=1000;
INSERT OVERWRITE TABLE employees
PARTITION (country, state)
SELECT ..., se.cty, se.st
FROM staged_employees se;

总结

使用from .. insert.. select ..where结构可以从一个数据表中抽取数据,将结果插入到不一样的表和分区中,而使用动态分区可以让hive根据select最末几个位置的值自动设定目标分区的值,使用动态分区须要设定一些hive运行参数

相关文章
相关标签/搜索