Hive 分区 分桶使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZYC88888/article/details/79131255

 为了对表进行合理的管理以及提高查询效率,Hive可以将表组织成“分区”。

  分区是表的部分列的集合,可以为频繁使用的数据建立分区,这样查找分区中的数据时就不需要扫描全表,这对于提高查找效率很有帮助。

    分区是一种根据“分区列”(partition column)的值对表进行粗略划分的机制。Hive中的每个分区对应数据库中相应分区列的一个索引,每个分区对应着表下的一个目录,在HDFS上的表现形式与表在HDFS上的表现形式相同,都是以子目录的形式存在。

 

  一个表可以在多个维度上进行分区,并且分区可以嵌套使用。建分区需要在创建表时通过PARTITIONED BY子句指定,例如:

CREATE TABLE logs(
timestamp BIGINT,
line STRING
)
PARTITIONED BY (date STRING,country STRING);

 

  在将数据加载到表内之前,需要数据加载人员明确知道所加载的数据属于哪一个分区。

  使用分区在某些应用场景下能给有效地提高性能,当只需要遍历某一个小范围内的数据或者一定条件下的数据时,它可以有效减少扫描数据的数量,前提是需要将数据导入到分区内。

  注意:PARTITONED BY子句中定义的列是表中正式的列(分区列),但是数据文件内并不包含这些列

 在Hive里,为什么要分区?

       庞大的数据集可能需要耗费大量的时间去处理。在许多场景下,可以通过分区或切片的方法减少每一次扫描总数据量,这种做法可以显著地改善性能。

数据会依照单个或多个列进行分区,通常按照时间、地域或者是商业维度进行分区。比如vido表,分区的依据可以是电影的种类和评级,另外,按照拍摄时间划分可能会得到更一致的结果。为了达到性能表现的一致性,对不同列的划分应该让数据尽可能均匀分布。最好的情况下,分区的划分条件总是能够对应where语句的部分查询条件。

  Hive的分区使用HDFS的子目录功能实现。每一个子目录包含了分区对应的列名和每一列的值。但是由于HDFS并不支持大量的子目录,这也给分区的使用带来了限制。我们有必要对表中的分区数量进行预估,从而避免因为分区数量过大带来一系列问题。

  Hive查询通常使用分区的列作为查询条件。这样的做法可以指定MapReduce任务在HDFS中指定的子目录下完成扫描的工作。HDFS的文件目录结构可以像索引一样高效利用。


Hive还可以把表或分区,组织成桶。将表或分区组织成桶有以下几个目的:

  第一个目的是为看取样更高效,因为在处理大规模的数据集时,在开发、测试阶段将所有的数据全部处理一遍可能不太现实,这时取样就必不可少。

  第二个目的是为了获得更好的查询处理效率。

 

        桶为了表提供了额外的结构,Hive在处理某些查询时利用这个结构,能给有效地提高查询效率。

        桶是通过对指定列进行哈希计算来实现的,通过哈希值将一个列名下的数据切分为一组桶,并使每个桶对应于该列名下的一个存储文件

    在建立桶之前,需要设置hive.enforce.bucketing属性为true,使得hive能识别桶。

  以下为创建带有桶的表的语句:

CREATE TABLE bucketed_user(
id INT,
name String
)
CLUSTERED BY (id) INTO 4 BUCKETS;

   向桶中插入数据,这里按照用户id分成了4个桶,在插入数据时对应4个reduce操作,输出4个文件。

分区中的数据可以被进一步拆分成桶,bucket,不同于分区对列直接进行拆分,桶往往使用列的哈希值进行数据采样。

在分区数量过于庞大以至于可能导致文件系统崩溃时,建议使用桶。

  桶的数量是固定的。

  Hive使用基于列的哈希函数对数据打散,并分发到各个不同的桶中从而完成数据的分桶过程。

  注意,hive使用对分桶所用的值进行hash,并用hash结果除以桶的个数做取余运算的方式来分桶保证了每个桶中都有数据,但每个桶中的数据条数不一定相等

  哈希函数的选择依赖于桶操作所针对的列的数据类型。除了数据采样,桶操作也可以用来实现高效的Map端连接操作。

   记住,分桶比分区,更高的查询效率

如何进行桶操作?

  例子1

1、创建临时表 student_tmp,并导入数据。

hive> desc student_tmp;
hive> select * from student_tmp;

 2、创建 student 表。经过分区操作过后的表已经被拆分成2个桶。

复制代码
create table student(
id int,
age int,
name string
)
partitioned by (stat_date string)
clustered by (id) sorted by(age) into 2 bucket
row format delimited fields terminated by ',';
复制代码

  分区中的数据可以被进一步拆分成桶!!!正确理解

  所有,桶,先partitioned by (stat_date string),再,clustered by (id) sorted by(age) into 2 bucket 

 3、设置环境变量。

hive> set hive.enforce.bucketing=true;

 4、插入数据

hive> from student_tmp
insert overwrite table student partition(stat_date='2015-01-19')
select id,age,name where stat_date='2015-01-18' sort by age;

 这都是固定的格式,一环扣一环的。


5、查看文件目录
$ hadoop fs -ls /usr/hive/warehouse/student/stat_date=2015-01-19/


6、查看 sampling 数据。
tablesample 是抽样语句,语法如下
tablesample(bucket x out of y)
y 必须是 table 中 BUCKET 总数的倍数或者因子。 

 

例子2

  在下面的例子中,经过分区操作过后的表已经被拆分成100个桶。

复制代码
CREATE EXTERNAL TABLE videos_b(
prodicer string,
title string,
category string
)
PARTITIONED BY(year int)
CLUSTERED BY(title)INTO 100 BUCKETS;
复制代码

  现在,我们开始填充这张带桶操作的表:

set hive.enfirce.bucketinig=true;
FROM videos
INSERT OVERWRITE TABLE videos_b
PARTITION(year=1999)
SELECT producer,title,string WHERE year=2009;

  如果不使用set hive.enforce.bucketing=true这项属性,我们需要显式地声明set mapred.reduce.tasks=100来设置Reducer的数量。

此外,还需要在SELECT语句后面加上CLUSTERBY来实现INSERT查询。

  下面是不使用桶设置的例子:

set mapred.reduce.tasks=100;
FROM videos
INSERT OVERWRITE TABLE videos_b
PARTITION(year=1999)
SELECT producer,title,string WHERE year=2009 CLUSTER BY title;

 

在Hive的文档中可以找到有关桶的更多细节:

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL

 

网上有篇关于hive的partition的使用讲解的比较好,转载了:

一、背景

1、在Hive Select查询中一般会扫描整个表内容,会消耗很多时间做没必要的工作。有时候只需要扫描表中关心的一部分数据,因此建表时引入了partition概念。

2、分区表指的是在创建表时指定的partition的分区空间。

3、如果需要创建有分区的表,需要在create表的时候调用可选参数partitioned by,详见表创建的语法结构。

二、技术细节

1、一个表可以拥有一个或者多个分区,每个分区以文件夹的形式单独存在表文件夹的目录下。

2、表和列名不区分大小写。

3、分区是以字段的形式在表结构中存在,通过describe table命令可以查看到字段存在,但是该字段不存放实际的数据内容,仅仅是分区的表示。

4、建表的语法(建分区可参见PARTITIONED BY参数):

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] [COMMENT table_comment] [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] [CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path]

5、分区建表分为2种,一种是单分区,也就是说在表文件夹目录下只有一级文件夹目录。另外一种是多分区,表文件夹下出现多文件夹嵌套模式。

a、单分区建表语句:create table day_table (id int, content string) partitioned by (dt string);单分区表,按天分区,在表结构中存在id,content,dt三列。

b、双分区建表语句:create table day_hour_table (id int, content string) partitioned by (dt string, hour string);双分区表,按天和小时分区,在表结构中新增加了dt和hour两列。

 

表文件夹目录示意图(多分区表):


6、添加分区表语法(表已创建,在此基础上添加分区):

ALTER TABLE table_name ADD partition_spec [ LOCATION 'location1' ] partition_spec [ LOCATION 'location2' ] ... partition_spec: : PARTITION (partition_col = partition_col_value, partition_col = partiton_col_value, ...)

用户可以用 ALTER TABLE ADD PARTITION 来向一个表中增加分区。当分区名是字符串时加引号。例:

ALTER TABLE day_table ADD PARTITION (dt='2008-08-08', hour='08') location '/path/pv1.txt' PARTITION (dt='2008-08-08', hour='09') location '/path/pv2.txt';

7、删除分区语法:

ALTER TABLE table_name DROP partition_spec, partition_spec,...

用户可以用 ALTER TABLE DROP PARTITION 来删除分区。分区的元数据和数据将被一并删除。例:

ALTER TABLE day_hour_table DROP PARTITION (dt='2008-08-08', hour='09');

8、数据加载进分区表中语法:

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]

例:

LOAD DATA INPATH '/user/pv.txt' INTO TABLE day_hour_table PARTITION(dt='2008-08- 08', hour='08'); LOAD DATA local INPATH '/user/hua/*' INTO TABLE day_hour partition(dt='2010-07- 07');

当数据被加载至表中时,不会对数据进行任何转换。Load操作只是将数据复制至Hive表对应的位置。数据加载时在表下自动创建一个目录,文件存放在该分区下。

9、基于分区的查询的语句:

SELECT day_table.* FROM day_table WHERE day_table.dt>= '2008-08-08';

10、查看分区语句:

hive> show partitions day_hour_table; OK dt=2008-08-08/hour=08 dt=2008-08-08/hour=09 dt=2008-08-09/hour=09

三、总结

1、在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 的数据都存储在最字集的目录中。

2、总的说来partition就是辅助查询,缩小查询范围,加快数据的检索速度和对数据按照一定的规格和条件进行管理。

——————————————————————————————————————

hive中关于partition的操作:
hive> create table mp (a string) partitioned by (b string, c string);
OK
Time taken: 0.044 seconds
hive> alter table mp add partition (b='1', c='1');
OK
Time taken: 0.079 seconds
hive> alter table mp add partition (b='1', c='2');
OK
Time taken: 0.052 seconds
hive> alter table mp add partition (b='2', c='2');
OK
Time taken: 0.056 seconds
hive> show partitions mp ;
OK
b=1/c=1
b=1/c=2
b=2/c=2
Time taken: 0.046 seconds
hive> explain extended alter table mp drop partition (b='1');
OK
ABSTRACT SYNTAX TREE:
  (TOK_ALTERTABLE_DROPPARTS mp (TOK_PARTSPEC (TOK_PARTVAL b '1')))

STAGE DEPENDENCIES:
  Stage-0 is a root stage

STAGE PLANS:
  Stage: Stage-0
      Drop Table Operator:
        Drop Table
          table: mp


Time taken: 0.048 seconds
hive> alter table mp drop partition (b='1');
FAILED: Error in metadata: table is partitioned but partition spec is not specified or tab: {b=1}
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask
hive> show partitions mp ;
OK
b=1/c=1
b=1/c=2
b=2/c=2
Time taken: 0.044 seconds
hive> alter table mp add   partition ( b='1', c = '3') partition ( b='1' , c='4');
OK
Time taken: 0.168 seconds
hive> show partitions mp ;
OK
b=1/c=1
b=1/c=2
b=1/c=3
b=1/c=4
b=2/c=2
b=2/c=3
Time taken: 0.066 seconds
hive>insert overwrite table mp partition (b='1', c='1') select cnt from tmp_et3 ;

hive>alter table mp add columns (newcol string);

 

location指定目录结构
hive> alter table alter2 add partition (insertdate='2008-01-01') location '2008/01/01';

hive> alter table alter2 add partition (insertdate='2008-01-02') location '2008/01/02';

展开阅读全文

没有更多推荐了,返回首页