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);