Hive 分区 – 分区表

分区原因:

  • 当我们load数据到表中的时候,会将数据存放到表对应的文件夹中
  • 但是随着时间的增长,表中的数据也会越来越多
  • 每次查询都会做全遍历的话,那么查询的时间也会越来越长
  • 我们可以根据常用属性建立子文件夹,将对应的数据存放到里面去
  • 这样我们查询数据直接去子文件夹中查询即可



一. ★ Hive的分区 partition

1. 创建分区 (分区层次)

1.1 单分区建表语句:

示例:

create table day_table(id int, content string) partitioned by (dt string) row format delimited fields terminated by ‘,’;


【单分区表,按天分区,在表结构中存在id,content,dt三列;以dt为文件夹区分】



1.2 双分区建表语句:

示例:

create table day_hour_table (id int, content string) partitioned by (dt string, hour string) row format delimited fields terminated by ‘,’;


【双分区表,按天和小时分区,在表结构中新增加了dt和hour两列;先以dt为文件夹,再以hour子文件夹区分】

注意:在创建 删除多分区等操作时一定要注意分区的先后顺序,他们是父子节点的关系。分区字段不要和表字段相同



2. 添加已创建表的分区

表已创建,在此基础上添加分区


语法:

ALTER TABLE table_name ADD partition_spec [ LOCATION ‘location1’ ] partition_spec [ LOCATION ‘location2’ ] …

示例:

ALTER TABLE day_table ADD PARTITION (dt=‘2008-08-08’, hour=‘08’)



3. 删除分区

语法:

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=‘08’);



4. 数据加载进分区表中

语法:

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表对应的位置。数据加载时在表下自动创建一个目录基于分区的查询的语句:SELECT day_table.
FROM day_table WHERE day_table.dt   >= ‘2008-08-08’;



5. 查看分区语句

示例:

hive> show partitions day_hour_table;



6. 重命名分区

语法:

ALTER TABLE table_name PARTITION partition_spec RENAME TO PARTITION partition_spec;

示例:

ALTER TABLE day_table PARTITION (tian=‘2018-05-01’) RENAME TO PARTITION (tain=‘2018-06-01’);



二. 动态分区&静态分区(加载方式)

静态分区

将数据指定到那个分区,对应的分区属性就是指定值
要求我们绝对不能放错数据

动态分区

就是现将数据存放到临时表
等我们将数据插入到分区的时候,查询临时表

动态分区流程示例:

--设置参数开启动态分区
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;

--创建角色表
create table t_role(
name string
)
partitioned by(
author string
) 
row format delimited 
fields terminated by ',' 
lines terminated by '\n';

--创建动态分区的临时表
create table t_role_tmp(
name string,
author string
) 
row format delimited 
fields terminated by ',' 
lines terminated by '\n';

--向临时表中载入数据
load data local inpath '/root/novel' into table t_role_tmp;

--动态插入数据
insert overwrite table t_role partition (author) select name from t_role_tmp;



三. Hive SerDe

Hive SerDe - Serializer and Deserializer SerDe 用于做序列化和反序列化。




Hive 桶分 – 桶分表

一. 分区 与 分桶

1. 分区:

  • 我们前面讲了分区,可以将常用属性进行分区,会自动创建文件夹
  • 然后相同分区的数据会放在同一个文件夹中,如果按照分区条件查询
  • 我们只需要查询指定的文件目录即可
  • 如果分区的数据散列比较好,这时分区就会产生很多分区,而且每个分 区数量寥寥无几
  • 所以列值范围比较固定的推荐使用分区



2. 分桶:

  • 算法类似于Map中的Partation操作(计算Key的Hash然后对ReduceNum取余)
  • 分区可以通过文件夹的方式将数据存放在不同的目录,但并不是所有的数据都适合分区
  • 那么我们可以将不适合分区的数据(散列均匀)进行分桶
  • 分桶一般会使用文件来管理数据,
    abs(hash(col))%bucketNum = x
    那么相同桶的数据会存放在同一个文件
  • 如果分桶的列值范围比较固定,不推荐使用分桶,即使桶再多也无法分出
  • 使用场景:
    数据抽样(10T–》10G*1000),适合前期调整算法
    Map-Join(两张表可以同时对一个常用查询列做相同个数的桶,那么比较的时候只需要一一对应即可)
           缩小分桶列的查询范围 empno=7788



二. 分桶表及应用场景

  • 分桶表是对列值取哈希值的方式,将不同数据放到不同文件中存储。
    对于hive中每一个表、分区都可以进一步进行分桶。
  • 由列的哈希值除以桶的个数来决定每条数据划分在哪个桶中。

适用场景:
数据抽样( sampling )、map-join



三.分桶步骤

1.开启支持分桶

set hive.enforce.bucketing=true;

默认:false;设置为true之后,mr运行时会根据bucket的个数自动分配reduce task个数。(用户也可以通过mapred.reduce.tasks自己设置reduce任务个数,但分桶时不推荐使用)


注意:一次作业产生的桶(文件数量)和reduce task个数一致。



2.往分桶表中加载数据

insert into table bucket_table select columns from tbl;

insert overwrite table bucket_table select columns from tbl;



3.桶表 抽样查询

select * from bucket_table tablesample(bucket 1 out of 4 on columns);



3.1 TABLESAMPLE语法:

TABLESAMPLE(BUCKET x OUT OF y)
x:表示从哪个bucket开始抽取数据
y:必须为该表总bucket数的倍数或因子



3.2 创建普通表
--示例:
CREATE TABLE psn31( id INT, name STRING, age INT) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

测试数据:
1,tom,11
2,cat,22
3,dog,33
4,hive,44
5,hbase,55
6,mr,66
7,alice,77
8,scala,88



3.3 创建分桶表
CREATE TABLE psnbucket( id INT, name STRING, age INT)
CLUSTERED BY (age) INTO 4 BUCKETS 
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';



3.4 加载数据:
insert into table psnbucket select id, name, age from psn31;



3.5 抽样
select id, name, age from psnbucket tablesample(bucket 2 out of 4 on age);