Hive 分区是一项特别强大的功能,通过分区可以将一个表划分为更多的 pieces(实际上一个分区物理上对应 HDFS 一个目录),从而可以以更细的粒度对数据进行管理和访问。
分区的优点如下:
- 分区也有助于查询性能的提升,我们可以直接查询某个分区的数据,避免了对表中的全量数据进行扫描。
- 借助分区,可以减少诸如 mapper 的数量,I/O 操作等系统资源。
分区的种类
分区可以进一步分为 静态分区 和 动态分区。
分区表的创建语法:
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS]
[db_name.]table_name
[(col_name data_type [column_constraint_specification] [COMMENT col_comment],
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)];
静态分区
静态分区需要明确指定向哪个分区写入。静态分区是可以 alter 的。
使用静态分区特性需要在 hive-site.xml 中设置属性 hive. mapred.mode = strict。
通过以下例子感受一下静态分区。
- 创建表
CREATE TABLE user_data (
user_id INT,
user_name string,
site_data string
) PARTITIONED BY (
date_dt string,
country string
);
create-table.png
- 插入数据
INSERT INTO TABLE user_data PARTITION(date_dt='2016-05-29', country='US') VALUES(201, 'Wick', 'Google');
INSERT INTO TABLE user_data PARTITION(date_dt='2016-05-20', country='UK') VALUES(202, 'John', 'Facebook');
INSERT INTO TABLE user_data PARTITION(date_dt='2016-05-20', country='UK') VALUES(203, 'Partick', 'Instagram');
INSERT INTO TABLE user_data PARTITION(date_dt='2016-05-29', country='UK') VALUES(204, 'Hema', 'Google');
INSERT INTO TABLE user_data PARTITION(date_dt='2016-05-28', country='INDIA') VALUES(205, 'Holi', 'Facebook');
INSERT INTO TABLE user_data PARTITION(date_dt='2016-05-20', country='RUSSIA') VALUES(206, 'Michael', 'Insatgram');
INSERT INTO TABLE user_data PARTITION(date_dt='2016-05-20', country='RUSSIA') VALUES(207, 'Chung', 'Instagram');
INSERT INTO TABLE user_data PARTITION(date_dt='2016-05-22', country='NEPAL') VALUES(208, 'Anna', 'Instagram');
show-partitions.png
默认情况下,表会创建在 HDFS 的 /user/hive/warehouse 路径(本例指定创建位置为 /user/spark/spark-sql-warehouse)。
由于我们的分区列为 date_dt 和 country 两列,相应的,可以在 HDFS 看到 user_data 的数据为以 date_dt 的取值作为第一级目录,country 的取值作为第二级目录进行存储。
hdfs-ls-1.png hdfs-ls-2.png动态分区
动态分区可以自动识别分区,不需要明确指定分区。例如,如果数据已经存储在一个非分区的表中,现在需要将数据转储到一个分区表中,此时动态分区比较适合。
动态分区比静态分区更加耗时,且分区不可修改。
使用动态分区特性需要在 hive-site.xml 中设置属性 hive.exec.dynamic.partition.mode= nonstrict。
通过以下例子感受一下动态分区:
准备两个表,user_data_dyn 和 user_log_data。user_data_dyn 是分区表,以 date_dt 列和 country 列作为分区列。user_log_data 为非分区表,接下来将数据从非分区表 user_log_data 转储到分区表 user_data_dyn 中。
- 创建表非分区表 user_log_data
CREATE TABLE user_log_data (
user_id int,
user_name string,
site_data string,
date_dt string,
country string
);
- 向 user_log_data 中插入测试数据
INSERT INTO TABLE user_log_data VALUES(1001, 'John', 'Google', '2016-04-27', 'US');
INSERT INTO TABLE user_log_data VALUES(1002, 'Eric', 'Facebook', '2016-04-28', 'US');
INSERT INTO TABLE user_log_data VALUES(1003, 'Annie', 'Instagram', '2016-04-28', 'UK');
INSERT INTO TABLE user_log_data VALUES(1005, 'Ming', 'Google', '2016-04-29', 'CHINA');
INSERT INTO TABLE user_log_data VALUES(1006, 'Li', 'Facebook', '2016-04-29', 'CHINA');
INSERT INTO TABLE user_log_data VALUES(1007, 'Sota', 'Insatgram', '2016-04-29', 'JAPAN');
INSERT INTO TABLE user_log_data VALUES(1008, 'Yuto', 'Instagram', '2016-04-27', 'JAPAN');
INSERT INTO TABLE user_log_data VALUES(1009, 'Anna', 'Instagram', '2016-04-28', 'AUSTRALIA');
INSERT INTO TABLE user_log_data VALUES(1010, 'Ricky', 'Facebook', '2016-04-28', 'AUSTRALIA');
- 创建分区表 user_data_dyn
CREATE TABLE user_data_dyn (
user_id int,
user_name string,
site_data string
) PARTITIONED BY (
date_dt string,
country string
);
- 将数据从 user_log_data 转储到 user_data_dyn
SET hive.exec.dynamic.partition = true;
SET hive.exec.dynamic.partition.mode = nonstrict;
INSERT OVERWRITE TABLE user_data_dyn
PARTITION(date_dt, country)
SELECT user_id, user_name, site_data, date_dt, country FROM user_log_data;
可以看到动态分区已经基于 date_dt 和 country 自动创建:
dynamic-partitions.png- 分区删除
对 user_data_dyn 中的分区执行删除操作,感受一下分区的便捷。不知道为什么,就想删掉那个叫 JAPAN 的 country:
alter table user_data_dyn drop partition (date_dt='2016-04-27', country='JAPAN');
drop-partitions.png
最后对 静态分区 和 动态分区 做一下对比:
分区方式 | 优点 | 缺点 |
---|---|---|
静态分区 | 速度快,分区设定后可以更改 | 需要明确指定分区 |
动态分区 | 速度慢,分区不可更改 | 自动创建分区 |
网友评论