hive —— 分区表
为了对表进行合理的管理以及提高查询效率,Hive可以将表组织成“分区”。一个分区实际上就是表下的一个目录,一个表可以在多个维度上进行分区,分区之间的关系就是目录树的关系。
通过PARTITIONED BY子句指定,分区的顺序决定了谁是父目录,谁是子目录。
例如:partitioned by(Field1,Field2,…),那么数据在hdfs上的存放路径是:
默认表路径/Field1=var1/Field=var2
hive分区表有静态分区和动态分区两种。
静态分区:
由用户手动添加分区表
建表:
1、直接建表
create [TEMPORARY] [EXTERNAL] table [IF NOT EXISTS] [db.name.] 表名
(
列名 数据格式
...
) partitioned by(列名 数据类型,...)
注意:分区字段不能是表里的字段!否则会报错:FAILED: Error in semantic analysis: Column repeated in partitioning columns(FAILED:语义分析错误:分区列中重复列)
此时建立的是一个主表,分区表还没有建立。
外部表建立分区表和内部表一样,区别只是在外部表需要添加EXTERNAL修饰词。
外部表在删除分区时,只会删除元数据,分区的目录和数据依然存在。内部表会把元数据、目录、数据一并删除。
2、CTAS
3、like建表
添加分区表:
ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION partition_spec [LOCATION 'location'][, PARTITION partition_spec [LOCATION 'location'], ...];
partition_spec:
: (partition_column = partition_col_value, partition_column = partition_col_value, ...)
例:
alter table t1 add [if not exists] partition (field1=var1,field2=var2,...) [location '路径']
partition (field1=var11,field2=var22,...) [location '路径']...
注意:hive0.7版本不能一个语句添加多个分区,以上语句只会添加第一个分区。
或者通过插入数据并添加分区:insert overwrite/into … select …
注:load方法加载数据不能真正地添加分区,即使语句中有分区字段的定义。
插入数据有两种方式:
1、load 文件数据
load data [local] inpath '数据文件路径' [overwrite] into table 表名 partition (partcol1=val1, partcol2=val2 ...)
注:加载操作目前是纯粹的复制/移动操作,将数据文件移动到与Hive表对应的位置。所以它不会真正地创建分区表。
3.0版本后:
如果表有分区,则load命令没有分区,那么load将被转换为INSERT AS SELECT,并假设最后一组列是分区列。如果文件不符合预期的模式,它将抛出一个错误。
让数据文件和分区表关联上的方式有:
- 先创建hdfs目录,再上传文件,然后刷新分区表的元数据(MSCK REPAIR TABLE 表名)。
- 先创建hdfs目录,再上传文件,然后创建分区(alter table 表名 add partition。。。)
- 先创建hdfs目录,然后通过load语句加载数据文件。
2、insert…select
insert overwirte/into table 表名 partition (partcol1=val1, partcol2=val2 ...) select * from 表名
动态分区:
静态分区需要手动一条一条地添加分区,指定分区字段的值。在分区表特别多的时候会很麻烦。
动态分区可以根据查询到的表的字段进行分区。
动态分区需要设置hive的几个参数:
- 启动动态分区功能,hive3.0版本前默认false,3.0及以后版本默认true
set hive.exec.dynamic.partition=true; - 分区模式,默认strict,严格模式规定至少一个静态分区字段。
set hive.exec.dynamic.partition.mode=nostrict; - 最大动态分区数,默认1000,总分区数超过限制数量时,任务会报错。
set hive.exec.max.dynamic.partitions=1000 - 表示每个maper或reducer可以允许创建的最大动态分区个数,默认是100,超出则会报错
set hive.exec.max.dynamic.partitions.pernode=100 - 全局可以创建的最大文件个数,超出报错
set hive.exec.max.created.files =10000(默认) - 如果动态分区插入生成空结果,是否引发异常
hive.error.on.empty.partition=false(默认)
静态分区需要在插入数据时指定分区字段的值,动态分区则不需要,只要让select语句的最后几个字段和分区字段匹配上即可:
insert overwrite/into table 表名 partition(partcol1, partcol2, ...) select field1,fleld2,...,partcol1,partcol2... from 表名 [where ...]
也可以指定其中几个分区字段为静态分区:
例:分区字段partcol1,partcol2指定分区值,partcol3等动态分区
insert overwrite/into table 表名 partition(partcol1=val1, partcol2=val2, partcol3...) select field1,fleld2,...,partcol3,... from 表名 [where ...]
为了让分区列的值相同的数据尽量在同一个mapreduce中,这样每一个mapreduce可以尽量少的产生新的文件夹,可以借助distribute by的功能,将分区列值相同的数据放到一起,这样也可以大量减少每个reducer创建的分区个数,防止超过hive.exec.max.dynamic.partitions.pernode的数量限制:
insert overwrite/into table 表名 partition(partcol1, partcol2, partcol3...) select field1,fleld2,...,partcol3,... from 表名 [where ...] distribute by partcol1,partcol2,partcol13...
其他操作
删除分区
使用alter table…drop partition语句删除对应分区:
alter table 表名 drop [IF EXISTS] partition(countrypartcol1=val1, partcol2=val2 ...) [IGNORE PROTECTION] [PURGE];
外部表只删除元数据信息,不会删除目录和数据。内部表会把元数据、目录和数据都删除。
您可以使用 ALTER TABLE DROP PARTITION 删除表的分区。 这将删除此分区的数据和元数据。 如果配置了 Trash,数据实际上会移动到 .Trash/Current 目录,除非指定 PURGE,但元数据完全丢失。
对于受 NO_DROP CASCADE 保护的表,您可以使用谓词 IGNORE PROTECTION 删除指定的分区或分区集(IGNORE PROTECTION 在 2.0.0 及更高版本中不再可用。 此功能被 Hive 提供的多个安全选项之一取代。)
ALTER TABLE table_name DROP [IF EXISTS] PARTITION partition_spec IGNORE PROTECTION;
无论保护状态如何,上述命令都会删除该分区。
如果指定了 PURGE,则分区数据不会进入 .Trash/Current 目录,因此在发生错误的 DROP 时无法检索(1.2.0版本之后可用):
LTER TABLE table_name DROP [IF EXISTS] PARTITION partition_spec PURGE; -- (Note: Hive 1.2.0 and later)
也可以使用表属性 auto.purge=true 指定清除选项。
在 Hive 0.7.0 或更高版本中,如果分区不存在,DROP 将返回错误,除非指定了 IF EXISTS 或配置变量 hive.exec.drop.ignorenonexistent 设置为 true。
归档分区文件
由于 HDFS 的设计,文件系统中文件的数量直接影响到 namenode 中的内存消耗。虽然对于小集群来说通常不是问题,但当有超过 50-1 亿个文件时,内存使用可能会达到单台机器上可访问内存的限制。在这种情况下,文件越少越好。
使用Hadoop Archives是减少分区中文件数量的一种方法。Hive 具有将现有分区中的文件转换为 Hadoop 存档 (HAR) 的内置支持,以便曾经由 100 个文件组成的分区可以只占用大约 3 个文件(取决于设置)。但是,权衡是查询可能会由于从 HAR 读取的额外开销而变慢。
请注意,归档不会压缩文件——HAR 类似于 Unix tar 命令。
ALTER TABLE table_name ARCHIVE PARTITION partition_spec; #开启归档
ALTER TABLE table_name UNARCHIVE PARTITION partition_spec; #取消归档
详细用法见:LanguageManual Archiving:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Archiving
修改分区
alter table 表名 partition(partcol1=val1, partcol2=val2, partcol3...) set location "new location";
alter table 表名 partition(partcol1=val1, partcol2=val2, partcol3...) rename to partition (partcol1=new val1, partcol2=new val2, partcol3...)
#此语句更改表(或分区)的文件格式。该操作仅更改表元数据。 任何现有数据的转换都必须在 Hive 之外完成。
alter table 表名 partition(partcol1=val1, partcol2=val2, partcol3...) set FILEFORMAT file_format
ALTER TABLE table_name TOUCH [PARTITION partition_spec] ;
添加表字段
alter table table_name partition(partition_name='分区值') add columns(column_name string);
交换分区
分区可以在表之间交换(移动)。该语句允许您将一个分区中的数据从一个表移动到另一个具有相同模式但不具有该分区的表。
ALTER TABLE <dest_table> EXCHANGE PARTITION (<[partial] partition spec>) WITH TABLE <src_table>
注:
- 目标表不能包含要交换的分区。
- 如果存在索引,操作将失败。
- 不允许事务表作为源或目标使用交换分区。或者,使用LOAD DATA或INSERT OVERWRITE命令在事务表之间移动分区。
- 此命令要求源表名和目标表名具有相同的表模式。如果模式不同,则抛出以下异常:
The tables have different schemas. Their partitions cannot be exchanged
压缩分区
在 Hive 版本 0.13.0 及更高版本中,当使用事务时,ALTER TABLE 语句可以请求压缩表或分区。从 Hive 版本 1.3.0 和 2.1.0 开始,当使用事务时,ALTER TABLE … COMPACT 语句可以包含一个 TBLPROPERTIES 子句,用于更改压缩 MapReduce 作业属性或覆盖任何其他 Hive 表属性。
ALTER TABLE table_name [PARTITION (partition_key = 'partition_value' [, ...])]
COMPACT 'compaction_type'[AND WAIT]
[WITH OVERWRITE TBLPROPERTIES ("property"="value" [, ...])];
通常,在使用 Hive 事务时不需要请求压缩,因为系统会检测到它们的需求并启动压缩。但是,如果关闭表的压缩,或者您想在系统不会选择的时间压缩表,则 ALTER TABLE 可以启动压缩。默认情况下,该语句将排队请求压缩并返回。要查看压缩的进度,请使用 SHOW COMPACTIONS。从 Hive 2.2.0 开始,可以指定“AND WAIT”以具有操作块,直到压缩完成。
compaction_type 可以是 MAJOR 或 MINOR。
合并分区小文件
在 Hive 版本 0.8.0 RCFile 中添加了对使用 concatenate 命令快速块级合并小型 RCFile 的支持。 在 Hive 版本 0.14.0 ORC 文件中,添加了使用 concatenate 命令对小型 ORC 文件进行快速条带级合并的支持。
ALTER TABLE table_name [PARTITION (partition_key = 'partition_value' [, ...])] CONCATENATE;
如果表或分区包含很多小的 RCFiles 或 ORC 文件,那么上面的命令会将它们合并成更大的文件。 在 RCFile 的情况下,合并发生在块级别,而对于 ORC 文件,合并发生在stripe 级别,从而避免解压缩和解码数据的开销。
其他操作
1,把一个分区打包成一个har包
alter table employees archive partition (country="china",state="Asia")
2, 把一个分区har包还原成原来的分区
alter table employees unarchive partition (country="china",state="Asia")
3, 保护分区防止被删除
alter table employees partition (country="china",state="Asia") enable no_drop [CASCADE]
4,保护分区防止被查询
alter table employees partition (country="china",state="Asia") enable offline
5,允许分区删除和查询
alter table employees partition (country="china",state="Asia") disable no_drop [CASCADE]
alter table employees partition (country="china",state="Asia") disable offline
可以在表或分区级别设置对数据的保护。 启用 NO_DROP 可防止删除表。 启用OFFLINE 可以防止查询表或分区中的数据,但仍然可以访问元数据。
如果表中的任何分区启用了 NO_DROP,则该表也不能被删除。 相反,如果一个表启用了 NO_DROP,那么分区可能会被删除,但是 NO_DROP CASCADE 分区也不能被删除,除非 drop partition 命令指定了 IGNORE PROTECTION。
注:no_drop和offline功能在hive2.0已删除。此功能被 Hive 提供的多个安全选项之一取代。
发现分区
Hive Metastore中自动发现并同步分区元数据。
当创建外部分区表时,discover.partitions”=“true” 表属性被自动添加。对于内部分区表,可以手动添加分区表属性”discover.partitions”。当Hive Metastore Service (HMS)在远程服务模式下启动时,一个后台线程(PartitionManagementTask)每300秒定时调度一次(可通过Metastore .partition.management.task.frequency config进行配置),该线程会寻找表属性”discover.partitions”=”true”的表,并在同步模式下执行MSCK修复。如果表是一个事务表,那么在执行msck修复之前,将为该表获取排他锁。有了这个表属性,“MSCK REPAIR table table_name SYNC PARTITIONS”不再需要手动运行。
该功能在hive4.0版本添加。
分区保留
表属性**“partition.retention.period”**现在可以为分区表指定保留间隔。当指定了保留间隔时,在HMS中运行的后台线程(请参阅Discover Partitions部分)将检查分区的年龄(创建时间),如果分区的年龄大于保留时间,它将被删除。在保留期之后删除分区也会删除该分区中的数据。例如,如果一个带有“date”分区的外部分区表带有表属性 “discover.partitions”=”true”和“partition.retention。Period “=“7d”,表示只保留最近7天内创建的分区。
Recover Partitions (MSCK REPAIR TABLE)
hive在其元数据中为每个表存储一个分区列表。
如果新的分区直接添加到HDFS(通过hdfs命令hadoop fs -put )或从HDFS删除,元数据不会意识到这些分区信息的变化,除非用户为每个这样的分区运行ALTER TABLE table_name ADD/DROP 分区命令。
但是,用户可以使用修复表选项运行 Metastore 检查命令:
MSCK [REPAIR] TABLE table_name [ADD/DROP/SYNC PARTITIONS];
这会将有关分区的元数据更新到 Hive metastore,用于尚未存在此类元数据的分区。
MSC 命令的默认选项是 ADD PARTITIONS。 使用此选项,它会将 HDFS 上存在但不在 Metastore 中的任何分区添加到 Metastore。
DROP PARTITIONS 选项将从 Metastore 中删除分区信息,该信息已从 HDFS 中删除。
SYNC PARTITIONS 选项等效于调用 ADD 和 DROP PARTITIONS。
当有大量未跟踪的分区时,可以提供批量运行 MSCK REPAIR TABLE 以避免 OOME(内存不足错误)的规定。 通过为属性 hive.msck.repair.batch.size 提供配置的批处理大小,它可以在内部批处理中运行。 该属性的默认值为零,这意味着它将一次执行所有分区。 不带 REPAIR 选项的 MSCK 命令可用于查找有关元数据不匹配元存储的详细信息。
注:从 Hive 1.3 开始,如果在 HDFS 上找到分区值中包含不允许字符的目录,MSCK 将抛出异常。 使用客户端上的 hive.msck.path.validation 设置来改变这种行为; “skip” 将简单地跳过目录。 “ignore” 无论如何都会尝试创建分区(旧行为)。 这可能有效,也可能无效。
Amazon Elastic MapReduce (EMR) 版本的 Hive 上的等效命令是:
ALTER TABLE table_name RECOVER PARTITIONS;
分区表修改表结构问题
参考: Hive分区表修改表结构的问题https://blog.csdn.net/hanhaixingchen/article/details/53744132
在使用 Alter语句修改 Hive 分区表结构的时候,会出现已存在的分区结构没有被修改的情况。比如说,新增了一个字段,但是向原有分区插入新增字段数据之后,查询却发现数据为 NULL,或者修改了一个字段类型,查询原有分区的时候发现数据没有被正确识别。
之所以会出现这种情况,是因为 Hive对应分区表表结构的修改,默认采用了限制模式。限制模式下,修改分区表结构的时候,只会对修改后新增的分区有效,修改表结构前已存在的分区不受影响。对应的,Hive也提供了级联修改的命令,在Alter 语句后添加 cascade参数,就可以连同过去存在的分区一起修改表结构(注意:Hive在0.15 版本之后才提供此参数)。
其他注意:
1、虽然目前对分区列的数据类型没有限制,但是允许非原始数据类型列作为分区列可能没有意义。动态分区列的类型应该从表达式派生出来。数据类型必须能够转换为字符串,以便在HDFS中保存为目录名。
2、分区列值到目录名的转换:
在将列值转换为字符串之后,我们仍然需要将字符串值转换为有效的目录名。一些原因是:
- 字符串长度在理论上是无限的,但是HDFS/local FS目录名长度是有限的。
- 字符串值可以包含在FS路径名中保留的特殊字符(例如’/‘或’…’)。
- 我们应该做什么分区列对象检查?
- 我们需要定义一个UDF(例如hive_qname_partition(T.part_col))来接受一个基本类型的值,并将其转换为一个限定的分区名。