一:hive引入静态分区的意义
目前主流离线数据仓库都在使用hive,最初由谷歌工程师开发,后面贡献给apache。使我们在处理大数据时,需要写大量的map/reduce程序当中解脱出来,只需要使用简单易于理解的hive sql就可以了,这使得大数据的离线处理变得简单易上手,并且更好维护。要理解hive引入分区的含义,得要了解hive框架的结构图,其实hive只是一个负责解析hive sql的框架,底层一般使用HDFS来进行存储操作(当时也可以使用其他的,详情参考官网hive hbase集成与Hive Accumulo集成)。hive的元数据默认是存储在derby数据库上,但是一般都会修改成mysql来进行存储。hive引入分区最主要的原因是可以实现在海量数据当中快速检索到需要的数据。分区表对应的HDFS上的目录跟非分区表有一点区别,主要是体现在#{hive库表目录}/根分区名/叶子分区名,hive支持多级分级,分区层级越多,相对来说,HDFS的目录就越深。对分区表进行筛选数据时只要指定分区,程序就能解析并映射到对应的目录文件,而不需要全文检索,大大加快了检索的速度。当然hive分区在数据相关工程方面也有着其意义,目前企业级的数据仓库都是会按照分区来维护数据表,比如根据天/小时等。
二:hive引入动态分区的意义以及如何使用
动态分区较之静态分区,主要是为了解决在某种场景下需要从子表抽取大量带分区的数据到另外一张表,如果没有动态分区,可能需要像如下这样操作(引用于hive官网):
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='US')
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'US'
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='CA')
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'CA'
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country='UK')
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip WHERE pvs.country = 'UK';
在前面的示例中,用户必须知道要插入哪个分区,并且在一个插入语句中只能插入一个分区。如果要加载到多个分区,则必须使用多插入语句。如果分区数非常多的话,那将是非常繁琐的,并且还有非常不是想发生的一点是:一条hive sql语句,就独立解析成一个job,伴随着大量的map/reduce程序,如果这样操作的话,会带来较大的性能开销。
如果使用动态分区的话,需要像如下这样操作:
INSERT OVERWRITE TABLE page_view PARTITION(dt='2008-06-08', country)
SELECT pvs.viewTime, pvs.userid, pvs.page_url, pvs.referrer_url, null, null, pvs.ip, pvs.country
这种方式大大的提高的用户写hive sql的效率,并且也提高了执行的效率。如上图所示并非是全动态分区,根分区为静态分区,叶子分区为动态分区,需要注意的是,静态分区其关联的值必须要partition当中指定好,而动态分区的值根据hive在执行过程当中获取动态分区列的值来动态产生分区。当然也可以实现全动态分区,道理是一样的。
三:动态分区使用注意事项
1.hive支持全动态分区,但是在使用前必须设置以下参数:
set hive.exec.dynamic.partition=true --表示开启全动态分区
set hive.exec.dynamic.partition.mode=nostrict --默认是strict(严格模式,必须至少包含一个静态分区)
2.如果是非全动态分区,必须要将静态分区放在根分区,拿page_view举例,不允许partition(dt,country ='US')这样写。
3.当动态分区列中已经存在非空分区时(例如,在某些dt根分区下存在country ='CA'),如果动态分区插入看到相同的值(例如'CA'),它将被覆盖。)输入数据中。这符合“插入覆盖”的语义。但是,如果分区值“ CA”未出现在输入数据中,则现有分区将不会被覆盖。
4.由于Hive分区对应于HDFS中的目录,因此分区值必须符合HDFS路径格式(Java中的URI)。URI中具有特殊含义的任何字符(例如'%',':','/','#')都将以'%'进行转义,后跟2个字节的ASCII值。
5.如果输入列的类型不同于STRING,则其值将首先转换为STRING,以用于构造HDFS路径。
6.如果输入列的值为NULL或空字符串,则该行将放入一个特殊分区,其名称由配置单元参数hive.exec.default.partition.name控制。
7:动态分区插入可能会占用大量资源,因为它可能会在短时间内生成大量分区。为了使自己安全,我们定义了三个参数:
hive.exec.max.dynamic.partitions.pernode(默认值为100)是每个映射器或化简器可以创建的最大动态分区。如果一个映射器或缩减器创建的阈值多于该阈值,则会从映射器/缩减器中引发致命错误(通过计数器),并且整个工作将被杀死。
hive.exec.max.dynamic.partitions(默认值为1000)是一个DML可以创建的动态分区的总数。如果每个映射器/缩减器未超过限制,但动态分区的总数未超过限制,则在作业结束时会引发异常,然后才将中间数据移至最终目标。
hive.exec.max.created.files(默认值为100000)是所有映射器和化简器创建的最大文件总数。每当创建新文件时,每个映射器/缩减器都会更新Hadoop计数器,从而实现此目的。如果总数超过hive.exec.max.created.files,将引发致命错误并杀死作业。
网友评论