Hive SQL之分区表与分桶表

  Hive sql是Hive 用户使用Hive的主要工具。Hive SQL是相似于ANSI SQL标准的SQL语言,可是二者有不彻底相同。Hive SQL和Mysql的SQL方言最为接近,可是二者之间也存在着显著的差别,好比Hive不支持行级数据的插入、更新和删除,也不支持事务操做。java

  注: HIVE 2.*版本以后开始支持事务功能,以及对单条数据的插入更新等操做sql

Hive的相关概念

  • Hive数据库

     Hive中的数据库从本质上来讲仅仅就是一个目录或者命名空间,可是对于具备不少用户和组的集群来讲,这个概念很是有用。首先,这样能够避免表命名冲突;其次,它等同于与关系型数据库中数据库的概念,是一组表或者表的逻辑组,很是容易理解数据库

  • Hive表

    Hive中的表和关系型数据库中table概念是相似的,每一个table在Hive中都有一个相应的目录存储数据。若是说,你没有指定表的数据库,那么Hive会经过{HIVE_HOME}/conf/hive_site.xml配置文件中的hive.metastore.warehouse.dir属性来使用默认值(通常是/usr/hive/warehouse,也能够根据实际状况来进行修改该配置),全部的table都保存在这个目录中。ide

    Hive中的表分为两类,分别为内部表外部表工具

    • 内部表(managed table)

      内部表,也即Hive管理的表,Hive内部表的管理包括逻辑以及语法上的,也包含实际物理意义上的,也就是说,建立Hive内部表后,表中的数据其实是存储在表所在的目录内,由Hive自己来管理,什么意思呢?也就是说,若是你想删除表的话,那么,连同表的物理数据,元数据等会一并删除。举个栗子:oop

  create table managed_table(name string,age int);
  load data inpath '/hadoop/guozy/data/user.txt' into table managed_table;

  第一条语句,建立一张简单的内部表,测试

  第二条语句,将hdfs://hadoop/guozy/data/user.tx 移动到Hive对应的目录hdfs://user/hive/warehouse/managed_table/这个目录中。注意,这里是移动,并不是复制spa

  移动数据是很是快的,由于Hive不会对数据是否符合定义的Schema作校验,这个工做一般在读取的时候进行(即Schema on Read),此时咱们在执行删除操做:code

drop table managed_table;

  在执行这条语句以后,其物理数据和表的元数据都会被删除。    orm

    • 外部表(external table)

      相对于内部表来讲,其管理仅仅是在逻辑和语法意义上的,实际的数据并不是由Hive自己来管理,而是交给了HDFS。当建立一个外部表的时候,仅仅是指向一个外部目录而已。若是你想删除表,只是删除表的元数据信息,并不会对实际的物理数据进行删除。举个栗子:

create external table external_table (name string,age int) location '/hadoop/guozy/external_table';
load data inpath '/hadoop/guozy/data/user.txt' into table external_table;

  第一条语句,建立一张简单的外部表,这里与内部表的区别是,添加了关键字external和location数据位置

  第二条语句,向表中载入数据,会将hdfs://hadoop/guozy/data/user.tx 移动到Hive对应的目录hdfs://hadoop/guozy/external_table这个目录中

  对于Hive来讲,它不会校验外部表的数据目录是否存在。因此咱们彻底能够在建立表以后在建立数据。此时咱们在来删除该表:

drop table external_table;

  执行上面这条语句以后,Hive删除的仅仅是该表对应的元数据而已,并不会对实际的屋里数据进行删除,也就是说hdfs://hadoop/guozy/external_table这个目录下的数据不会被删除。

  • 分区和分桶

    Hive将表划分为分区(partition)表和分桶(bucket)表。

    分区可让数据的部分查询变得更快,也就是说,在加载数据的时候能够指定加载某一部分数据,并非全量的数据。

    分桶表一般是在原始数据中加入一些额外的结构,这些结构能够用于高效的查询,例如,基于ID的分桶可使得用户的查询很是的块。

    • 分区表 

      所谓的分区表,指的就是将数据按照表中的某一个字段进行统一归类,并存储在表中的不一样的位置,也就是说,一个分区就是一类,这一类的数据对应到hdfs存储上就是对应一个目录。当咱们须要进行处理的时候,能够经过分区进行过滤,从而只去部分数据,而不必取所有数据进行过滤,从而提高数据的处理效率。且分区表是能够分层级建立。

      分区表又分为静态分区表动态分区表两种:

      • 静态分区表:所谓的静态分区表指的就是,咱们在建立表的时候,就已经给该表中的数据定义好了数据类型,在进行加载数据的时候,咱们已经知道该数据属于什么类型,而且直接加载到该分区内就能够了。来看一个简单的分区表的建立语句(这里建立的是一张内部表):
hive> create table enter_country_people(id int,name string,cardNum string) partitioned by (enter_date string,country string);

         指定分区表关键字:partitioned by 

            这里的分区字段为:enter_date、country,也就是说,先按照enter_date进行分类,在enter_date的基础上,在按照country再次进行分类

         注意,这里的分区字段不能包含在表定义字段中,由于在向表中load数据的时候,须要手动指定该字段的值。

        接下来向表中载入数据,而且指定分区为enter_date='2019-01-02',country='china' 

hive> load data inpath '/hadoop/guozy/data/enter__china_people' into table enter_country_people partition (enter_date='2019-01-02',country='china');

         这样建立表以后的表目录结构是这样的:

        

        这里还有一个问题就是,涉及到载入数据的方式

        一、使用的是load命令,也就是我上面的方式,能够看到,在load数据以前,表中是没有这个分区(enter_date='2019-01-02',country='china')的。当执行了load命令以后,hive会自动建立该分区。这只是其中的一种方式,还有一种方式就是,咱们直接能够经过移动数据到该分区的目录下

        二、直接经过hdfs的mv命令移动数据到该分区指定的目录下。由于前面说过,所谓的分区只是对应到hdfs存储中的一个目录而已。最终数据查询仍是要到这个目录中去进行查询数据。可是这种方式有个前提就是,该分区所在的目录必须呀提早存在,注意,这里说的是对应的该目录存在。固然这个目录你能够手动mkdir,也能够经过hive添加分区的方式进行建立,这里又分为两种状况:

          a.经过hive添加分区的方式进行建立,例如:

hive> alter table enter_country_people add if not exists partition (enter_date='2019-01-03',country='US');

           经过这种方式添加分区以后,会生成这样一个目录:hdfs://user/hive/warehouse/2019-01-03/US,此时,咱们就能够直接使用hdfs的mv或cp命令将数据搂到该目录下。以后使用hive命令进行查询便可

          b.第二种方式就是,咱们先手动建立该目录:hdfs dfs -mkdir /user/hive/warehouse/2019-01-03/US,而后一样使用上面这种方式,将数据mv或cp到该目录下,可是,若是只是这样的话,你去使用hive命令查询数据,发现查不到,为何,由于hive查询数据是须要先到元数据表中找到对应数据的分区索引的,而后根据找到的分区索引,再去对应的目录中查找,可是才是咱们根本没有对hive的元数据进行操做,因此元数据中没有这个分区的信息,因此此时,咱们须要在增长一步操做,就是将该分区的信息添加到元数据库中,咱们使用hive的分区修复命令便可:

hive> msck repair table enter_country_people;

           执行上述命令以后,而后在进行数据查询,就没有什么问题了

      • 动态分区表:所谓的动态分区表,其实建表方式跟静态分区表没有区别,最主要的区别是在载入数据的时候,静态分区表咱们载入数据以前必须保证该分区存在,而且我么已经明确知道载入的数据的类型,知道要将数据加载到那个分区当中去,而动态分区表,在载入的时候,咱们事先并不知道该条数据属于哪一类,而是须要hive本身去判断该数据属于哪一类,并将该条数据加载到对应的目录中去。建表语句跟静态分区表的建表语句相同,这里再也不赘述,主要来看看数据的加载:

        对于动态分区表数据的加载,咱们须要先开启hive的非严格模式,而且经过insert的方式进行加载数据

hive> set hive.exec.dynamic.partition.mode=nonstrict;
hive> insert into table enter_country_people(user string,age int) partition(enter_date,country) select user,age,enter_date,country from enter_country_people_bak;

        注意:一、必须先开启动态分区模式为非严格模式

           二、这里在指定分区的时候,并无指定具体分区的值,而只是指定的分区的字段

           三、partition中的字段实际上是做为插入目标表中的一个字段,因此在从另一张表select的时候必须查询字段中包含索要分区的这个字段。

    • 分桶表

        在表或者分区中使用分桶一般有两个缘由,一个是为了高效的查询,另外一个则是为了高效的抽样。

        桶实际上是在表中加入了特殊的结构,hive在查询的时候能够利用这些结构来提升查询效率。好比,若是两个表根据相同的字段进行分桶,则在对这两个表进行关联的时候可使用map-side关联高效实现。前提是,关联的字段在分桶字段中出现才能够。先看下hive的分桶建表语句:

hive> create table user_bucket(id int comment 'ID',name string comment '姓名',age int comment '年龄') comment '测试分桶' clustered by (id) sorted by (id) into 4 buckets row format delimited fields terminated by '\t';

        上述语句,指定根据id字段进行分桶,而且分为4个桶,而且每一个桶内按照id字段升序排序,若是不加sorted by,则桶内不通过排序的,具体的分桶规则是怎样的呢?Hive是根据指定的分桶字段,上述语句中为id,根据id进行hash以后在对分桶数量4进行取余来决定该数据存放在哪一个桶中,所以每一个桶都是总体数据的随机抽样。

        在map-side关联操做中,两个表若是根据相同的字段进行分桶,在处理左表的bucket是,能够直接从外表对应的bucket中提取数据进行关联操做。map-side关联的两个表不必定须要彻底相同的bucket数量,只要成倍数便可。一样,Hive不会对数据是否知足表定义中的分桶进行校验,只有在查询时出现异常才会报错,因此通常,咱们将分桶的工做交给Hive本身来完成(设置hive.enforce.bucketing=true).

        载入数据:

        在载入数据的时候,须要注意一下,若是说咱们只是单纯的使用load语句进行将数据载入到表中的话,实际上是没有任何的分桶效果的,由于这样hdfs文件只有一个,像这样:

hive> load data inpath '/hadoop/guozy/data/user.txt' into table user_bucket;

        此时,咱们须要借助一个中间表,先将数据load到中间表中,而后经过insert的方式来向分桶表中载入数据:

hive> create table tmp_table (id int comment 'ID',name string comment '名字',age int comment '年龄') comment '测试分桶中间表' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' ;
hive> load data inpath '/hadoop/guoxb/data/user.txt' into table tmp_table;
hive> insert into user_bucket select * from tmp_table;

        这样就实现了分桶的效果,注意,分桶和分区的区别,分区体如今hdfs上的文件目录,而分桶则提如今hdfs是具体的文件,上述的语句中,最终会在hdfs上生成四个文件,而不是四个目录,若是当在次向该分桶表中insert数据后,会又增长4个文件,而不是在原来的文件上进行追加。

        通常状况下,建表分桶表的时候,咱们都须要指定一下排序字段,这样有一个好处就是,在每一个桶进行链接查询时,就变成了高效的归并排序了。

相关文章
相关标签/搜索