现在要用hive分析数据,同时要保证这些数据目录不能改变,就需要hive用外表的方式与这些数据进行关联。
示例:
但是,看下文件列表
一共108个待添加的目录,这样一个个添加太累人,有没有批量添加的方法呢?
Hive有个MSCK命令,可以扫描数据分区目录,修复元信息,目录与元信息不一致时,能自动更新。
但是,数据目录必须是Hive习惯路径格式:
同时,建表时指定LOCATION为分区目录的父目录:
这时,用命令
即可自动把所有的数据按dt分区,添加到gateway_analysis中。
由于我们的目录格式不符合,只能用ADD PARTITION的方式了。
为减少工作量,写了个shell脚本,自动添加 /data/logs/gateway 目录下所有的分区目录到gateway_analysis表中:
一、Hive only:加载分区数据的快捷方法
如果指定的分区不存在Hive将创建新的分区
这个命令将:
(1)如果不存在的话添加分区到表的元数据
(2)如果存在的话,创建子目录:/user/hive/warehouse/call_logs/call_date=2014-10-02
(3)移动HDFS文件call-20141002.log到分区子目录
二、查看、添加和移除分区
(1)查看当前表分区
(2)使用ALTER TABLE添加或删除分区
三、 从已存在的分区目录创建分区
(1)HDFS的分区目录可以在Hive或Impala之外进行创建和数据,比如:通过Spark或MapReduce应用
(2) Hive中使用MSCK REPAIR TABLE命令来为已存在的表创建分区
四、什么时候使用分区
下列情况使用分区
(1)读取整个数据集需要花费很长时间
(2)查询几乎只对分区字段进行过滤
(3)分区列有合理数量的不同的值
(4)数据生成或ETL过程是按文件或目录名来分段数据的
(5)分区列值不在数据本身
五、什么时候不使用分区
(1)避免把数据分区到很多小数据文件
– 不要对有太多惟一值的列进行分区
(2)注意:当使用动态分区时容易发生
– 比如:按照fname来分区客户表会产生上千个分区
六、 Hive进行分区
在旧的Hive版本中,动态分区默认没有启用 ,通过设置这两个属性启用:
但是在hive分区中我们应该注意一些问题,比如:
(1)注意:Beeline设置的Hive变量只在当前会话有效,系统管理员可以设置永久生效
(2)注意:如果分区列有很多唯一值,将会创建很多分区
另外,我们可以给Hive配置参数来限制分区数 :
(1) hive.exec.max.dynamic.partitions.pernode
查询在某个节点上可以创建的最大动态分区数,默认100
(2) hive.exec.max.dynamic.partitions
一个HiveQL语句可以创建的最大动态分区数 ,默认1000
(3)hive.exec.max.created.files
一个查询总共可以创建的最大动态分区数,默认1000000
hive 分区表:
分区字段的物理表现:
hive分区表 ,其真实的表现其实就是在 存储hive表的文件夹的下面,创建新的文件夹,
文件夹的名字是 分区字段=字段取值 这种格式的。
分区的优点:
当分区表的数据很大的时候,可以指定查询表格之中的部分数据。
设置表格分区字段需要的注意点:
1:分区字段的取值不要很多,因为这样会造成表的文件夹的下面会出现很多的小的文件夹
2: 一般可以将sql之中 where 之中出现的字段作为 分区的字段。(可以当作分区字段选取的一个参考)
查看表格是否是分区表:
desc formatted table_name
分区表的话 ,会有Partition Information
向分区表插入数据:
情况分为:
1:向表格之中插入数据,明确指定插入的分区的名字
2:向表格之中插入数据,不明确指定插入的数据的名字,而是根据插入的数据的某个字段的取值来自动决定数据
被插入到哪一个分区之中。被称为动态分区。
如何开启hive 动态分区的功能?
set hive.exec.dynamici.partition=true
hive 动态分区:有两种模式:
严格模式 和非严格模式
严格模式:
动态分区的时候,必须有一个分区是静态的。
非严格模式,对分区是否是静态的不在意。
如何设置 动态分区的模式?
set hive.exec.dynamic.partition.mode=nostrict
默认的模式是strict 严格模式。
插入数据时 明确指定需要插入的分区的值:
sql demo :
1:load data [local] inpath 'path' into table xxx partition(partition_fields partiton_type)
2:insert into table table_a partition(partition_fields partition_type)
select * from table_b [....]
使用insert 的时候 ,需要注意前后表的表的字段数目是匹配的,
如果表的前后字段是不匹配的话,那么就是会报错。
向分区表之中插入数据的时候,根据数据的某个字段的值,来创建分区,
以及决定数据被插入到哪一个分区之中。
sql demo:
对一个分区 进行动态分区:
首先要设置两个参数:
set hive.exec.dynamici.partition=true
set hive.exec.dynamic.partition.mode=nostrict
然后就是可以使用动态分区了。
分区值的推断,是根据后面查询的最后字段来决定的,只有一个分区,
那么就是查询的最后一个字段,如果是两个,那么就是从后往前的字段进行匹配。
insert into table pp partition(`date`) select name,age,`date` from par
这里的sql demo
是将par 的`date` 字段 作为pp表之中 `date`分区的取值。
部分动态分区:
就是多个分区,但是前面的分区的取值是取静态的,然后后面的分区的取值是未定的。
类似于 partition(country='china',city)
这里需要注意的是顺序,静态分区在前面,动态分区在后面。
然后就是多个分区,完全的动态分区:
完全动态分区的时候,就是使用后面select 查询的表进行分区数据的匹配。
、
动态分区在实际使用的时候会遇到的问题:
动态分区的一个使用场景:
首先加载数据到一个表格a之中,然后将这个表格之中再次转化到另外一个
表格b之中,表a转化到表b的时候,使用动态分区。
因为直接使用load 加载数据的时候,对于分区表而言,加载数据只能指定固定的分区名,
无法使用动态分区来加载数据。
相应的问题就是:
如果a表本身含有很多的文件,那么使用动态分区的时候,
那么在b表的时候,就是会产生很多的小文件。
原因如下:
如果 a表之中数据文件是200个,
那么动态分区的时候,可能会产生200个map,
然后一个map包含的数据之中,可能有多个分区的取值,
所以一个map 会产生多个文件。
所以后果就是,在新的b表之中的每个分区下面,会产生很多的小文件。
总结来说:不好的影响就是可能会产生很多的小文件。
解决的方式:
因为动态分区转化成为的mapredue job 是没有reduce,所以数目不好控制,
所以可以采用的方式,就是手动增加reduce的数目,
可以使用distributed by 来增加 reduce的数目。
insert into table table_a partition('partition_name')
select * from table_b
dirtribute by partitoin_name
但是这样的方式,就是可能导致 reduce之间包含的数据量的不均匀。
所以解决的方法就是:
distribute by rand()
使用hash 随机分区,这样的方式,来讲数据均匀分配到reduce之中。
然后每个reduce 会产生 分区取值数目的文件,
例子: reduce数目为 200 分区的取值数位24
那么最后产生的文件的数目就是 200* 24个文件。
其实可以通过exlpain 来解析sql的执行计划,这样的话,
可以看出是否具有reduce *** 作。
查询表的分区信息:
show partitions table_name
向分区表之中增加分区:
alter table table_name add partition(pfield=pvalue,...)
如果表格之中有多个分区的话,那么增加分区的时候,也是多个分区
一同增加的。
删除分区:
alter table table_name drop partition(pfield=pval)
分区信息修改:
分区信息的修改分为 分区名的修改 和 分区数据的修改 两种
分区名的修改
alter table table_name partition(pfield=pvalue) rename to partition(pfield=pvalue)
分区数据的修改:
alter table table_name partition(pfield=pvalue) set location 'data_location'
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)