分区字段的物理表现:
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'
摘要: Hive , Shell
Hive复制表包括两种
对于非分区表如果要完全复制一张表到另一张表,直接使用CREATE TABLE ... AS语句即可,比如以下复制一个表的两个字段以及字段的值到另一个表
对于分区表如果使用CREATE TABLE ... AS语句则分区失效,但是可以执行不报错,且字段和数据都能完全复制
以上有一张分区表,以dt字段作为分区,使用CREATE TABLE ... AS进行全表复制
检查表结构和表数据量都没有问题
检查分区,报错此表不是分区表,is not a partitioned table,但是在表结构中确实存在本来的分区字段dt,此时dt字段的分区功能失效,但是数据保留住了
分区表的全称复制且带有分区的 *** 作方法需要使用 LIKE 语句复制到分区信息,具体步骤如下
第一步复制得到一张空表,具有原表的表结构和分区信息
下一步使用hdfs命令 *** 作将原表在hdfs的存储路径复制到新表的路径, 一张表的存储路径是一个目录,该目录下还存在子目录,每一个子目录代表一个分区,在分区目录下就是数据文件,数据文件是part开头格式,由Hive的分桶策略将同一分区下的数据进行划分
复制语句采用 * 通配符将原表目录下所有文件复制到新表路径下,查看新表的hdfs路径下数据文件
此时新表虽然对应数仓目录下有数据文件,但是在Hive客户端还是查不到数据为空表, 因为一个个数据分区不存在在新表的元数据中,数据是以分区目录为单位聚合的,新表目前查不到一个分区则自然查不到数据
下一步修复表的分区元数据,使用 MSCK REPAIR TABLE 命令
由输出的执行过程可见MSCK REPAIR TABLE命令先检查了表的分区信息是否存在在元数据,然后对不存在的分区信息进行修复,修复后该表即可正常使用
MSCK REPAIR TABLE 的作用是 只需要只用这一个命令就可以 快速 , 自动化 地添加(修复)全部分区 ,在Hive中如果先建分区表,并且以数据拷贝到对应HDFS目录这种方式作为初始化,需要手动添加分区才能使用,如果分区过多,使用 ALTER TABLE ADD PARTITION 极为不变,下面做一下测试看ALTER TABLE ADD PARTITION是否也能完成分区表的完全复制
下一步采用手动添加1个分区dt='20201209'
验证了手动分区能够完成, MSCK REPAIR TABLE只是自动化的扫描一遍数仓目录下的分区信息(dt='20201209' 到 dt='20210317') ,如果编写一个Shell脚本也能实现如下
运行这个Shell脚本后能达到同样的效果,但是这个脚本执行了15分钟,需要频繁启动和关闭Hive进程
Hive的insert语句能够从查询语句中获取数据,并同时将数据Load到目标表中。现在假定有一个已有数据的表staged_employees(雇员信息全量表),所属国家cnty和所属州st是该表的两个属性,我们做个试验将该表中的数据查询出来插入到另一个表employees中。
由于使用了OVERWRITE关键字,目标表中原来相同partition中的所有数据被覆盖,如果目标表中没有partition,则整个表会被覆盖。
如果把OVERWRITE关键字删掉,或者替换成INTO,则hive会追加而不是替代原分区或原表中的数据,这个特性在Hive v0.8.0之后才支持。
当数据已经存在于hdfs上但不是我们想要的格式的时候,当进行的计算需要分好多步骤有必要存储中间数据的时候,或者原数据没有分区、有很多无效列需要过滤的时候,可以使用insert..select句型来完成这一转换过程。
由于一个国家有很多个省份,如果想根据(国家country,地区partition)两个维度对数据进行分区的话,这条SQL语句的执行个数应该等于地区的数目,比如中国有23个省就要对该SQL语句执行23次。因此hive对这个SQL语句进行了改造,只需要扫描一次原表就可以生成不同的输出(多路输出)。比如下面的SQL语句扫描了一次原始数据表,但是同时生成了3个省份的结果数据:
通过缩进可以很清楚的看到,我们扫描了一次staged_employees表但是执行了3次不同的insert语句,这条大SQL语句是这么执行的:先通过from staged_employees表获取一条记录,然后执行每一个select子句,如果select子句验证通过则执行相应的insert语句。注意这里的三条select子句是完全独立执行的,并不是if .. then .. else的关系,这就意味着这3条select子句在某种情况下可能同时通过where检测。
通过这种结构,原始表的数据能被拆分到目标表的不同partition中去。
如果原表的一条记录满足于其中一个给定的select .. where .. 子句,则该记录将被写到目标表的固定分区中。其实更进一步,每条Insert语句能将数据写到不同的数据表中,不管这个表是否分区都一样。
于是,就像一个过滤器一样,原表的一些数据被写到了很多输出地址,而剩下的数据会被丢弃。
当然,你也可以混用Insert overwrite和insert into两种不同的方法写出数据。
向动态分区插入数据
但是问题还是没有解决,中国有23个省,那么我们就需要写23个insert into .. select ..where子句,这非常不现实。于是hive的一种叫做动态分区的特性就出现了,它能够根据select出来的参数自动推断将数据插入到那个分区中去。本文上面的两种SQL语句设定分区的方式都叫做静态分区插入。
将上一个SQL语句进行改动,会得到以下简洁的新SQL语句:
hive先获取select的最后两个位置的se.cnty和se.st参数值,然后将这两个值填写到Insert语句partition中的两个country和state变量中,即动态分区是通过位置来对应分区值的。原始表select出来的值和输出partition的值的关系仅仅是通过位置来确定的,和名字并没有关系,比如这里se.cnty和county的名称完全没有关系。
上面的这条SQL语句是对两个分区同时进行了动态设定,如果staged_employees表中有100个国家,每个国家有100个地区,那么该SQL语句自动对每个国家和地区建立相应的partition并插入数据,如果用手写的话不现实。
只要位置正确,你可以混用动态分区和静态分区值设定,比如下面这个例子,你可以静态指定一个country值,但是state值采用动态的方法设定:
注意:静态分区值必须在动态分区值的前面!
使用hive动态分区的参数设定
动态分区功能默认是关闭的,而当它是打开状态时,默认会工作在“strict”模式下,这种模式下要求至少指定一个静态分区的值。这样做是为了防止设计了大量partition的糟糕情况,举个例子你使用时间戳来进行分区,竟然每一秒钟都产生一个分区!还有其他的一些属性设定用来限制类似的情况出现,如下表所示:
名称 默认值 描述
hive.exec.dynamic.partition false 设置为true用于打开动态分区功能
hive.exec.dynamic.partition.modestrict 设置为nonstrict能够让所有的分区都动态被设定,否则的话至少需要指定一个分区值
hive.exec.max.dynamic.partitions.pernode100 能被每个mapper或者reducer创建的最大动态分区的数目,如果一个mappre或者reducer试图创建多余这个值的动态分区数目,会引发错误
hive.exec.max.dynamic.partitions+1000 被一条带有动态分区的SQL语句所能创建的动态分区总量,如果超出限制会报出错误
hive.exec.max.created.files 100000 全局能被创建文件数目的最大值,专门有一个hadoop计数器来跟踪该值,如果超出会报错
举个例子,使用全动态分区的SQL语句序列如下所示,需要先设定一些必要的参数才可以:
总结
使用from .. insert.. select ..where结构能够从一个数据表中抽取数据,将结果插入到不同的表和分区中,而使用动态分区能够让hive根据select最末几个位置的值自动设定目标分区的值,使用动态分区需要设定一些hive运行参数。
转自 http://www.crazyant.net/1197.html
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)