hive数据定义是hive的基础知识,所包含的知识点有:数据仓库的创建、数据仓库的查询、数据仓库的修改、数据仓库的删除、表的创建、表的删除、内部表、外部表、分区表、桶表、表的修改、视图。在上一篇文章中介绍了一部分知识点,在本篇文章中将阐述剩下的知识点内容:内部表、外部表、分区表、分桶表、表的修改、视图。
不带EXTERNAL关键字创建的表是管理表,有时也称为内部表。Hive表是归属于某个数据仓库的,默认情况下Hive会将表存储在默认数据仓库中,也可以使用Use命令切换数据仓库,将所创建的表存储在切换后的数据仓库中。
删除内部表时,表的元数据和表数据文件同时被删除。
内部表(Internal table)也称为被Hive拥有和管理的受控表(Managed table)。
默认情况下创建的表就是内部表,Hive拥有该表的结构和文件。换句话说,Hive完全管理表(元数据和数据)的生命周期。
当删除内部表时,它会删除数据以及表的元数据。
创建内部表的示例代码:
--默认情况下 创建的表就是内部表
create table users(
id int,
name string,
age int,
city string
)row format delimited
fields terminated by ',';
可以使用DESC FORMATTED tablename,来获取表的元数据描述信息,从中可以看出表的类型。
例如:
外部表(External table)中的数据不是Hive拥有或管理的,只管理表元数据的生命周期。
要创建一个外部表,需要使用EXTERNAL语法关键字。
删除外部表只会删除元数据,而不会删除实际数据。在Hive外部仍然可以访问实际数据。
实际场景中,外部表搭配location语法指定数据的路径,可以让数据更安全。
示例代码:
--创建外部表 需要关键字 external
--外部表数据存储路径不指定 默认规则和内部表一致
--也可以使用location关键字指定HDFS任意路径
create external table users(
id int,
name string,
age int,
city string
)row format delimited
fields terminated by ',';
执行drop table tablename 命令,分别在Hive中和HDFS中查看效果。
Hive中的表信息全被删除,不管是内部表还是外部表。
而HDFS上,外部表对应的数据文件原封不动,内部表对应的数据文件连同文件夹一起被删除。
无论内部表还是外部表,Hive都在Hive Metastore中管理表定义、字段类型等元数据信息。
删除内部表时,除了会从Metastore中删除表元数据,还会从HDFS中删除其所有数据文件。
删除外部表时,只会从Metastore中删除表的元数据,并保持HDFS位置中的实际数据不变。
当需要通过Hive完全管理控制表的整个生命周期时,请使用内部表。
当数据来之不易,防止误删,请使用外部表,因为即使删除表,文件也会被保留。
在Hive建表的时候,可以通过location语法来更改数据在HDFS上的存储路径,使得建表加载数据更加灵活方便。
语法:LOCATION '
对于已经生成好的数据文件,使用location指定路径将会很方便。
Location关键字的作用
在创建外部表的时候,可以使用location指定存储位置路径,如果不指定会如何?
如果不指定location,外部表的默认路径也是位于/user/hive/warehouse,由默认参数控制。
创建内部表的时候,是否可以使用location指定?
内部表可以使用location指定位置的。
是否意味着Hive表的数据在HDFS上的位置不是一定要在/user/hive/warehouse下?
不一定,Hive中表数据存储位置,不管内部表还是外部表,默认都是在/user/hive/warehouse,当然可以在建表的时候通过location关键字指定存储位置在HDFS的任意路径。
现有3份结构化数据文件,分别记录了用户的姓名、年龄、省、城市信息。现要求通过建立一张表all_users,把3份文件同时映射加载,字段为id、name、age、province、city。
--默认情况下 创建的表就是内部表
create table all_users(
id int,
name string,
age int,
province string,
city string
)row format delimited
fields terminated by ',';
现要求查询来自河南,年龄大于18岁的人的数量,sql语句如下:
select count(*) from all_users where province=‘henan’ and age>18;
这样操作会有一些问题:
where语句的背后需要进行全表扫描才能过滤出结果,对于hive来说需要扫描每一个文件。如果数据文件个数特别多的话,扫描效率很慢也没必要。
本需求中,只需要扫描users_henan.txt文件即可,如何优化可以加快查询,减少全表扫描呢?
指定文件扫描和全表扫描,效率还是存在差异的。
当Hive表对应的数据量大、文件个数多时,为了避免查询时全表扫描数据,Hive支持根据指定的字段对表进行分区,分区的字段可以是日期、地域、种类等具有标识意义的字段。
比如把一整年的数据根据月份划分12个月(12个分区),后续就可以查询指定月份分区的数据,尽可能避免了全表扫描查询。
完整语法树对应位置:
分区表语法
注意:分区字段不能是表中已经存在的字段,因为分区字段最终也会以虚拟字段的形式显示在表结构上。
--分区表建表语法
CREATE TABLE table_name (
column1 data_type,
column2 data_type,
....)
PARTITIONED BY (partition1 data_type, partition2 data_type,…);
针对用户信息数据,重新创建一张分区表users_par,以sheng角色作为分区字段。
create table users_par(
id int,
name string,
age int,
province string,
city string
) partitioned by (sheng string)
row format delimited
fields terminated by “,";
所谓静态分区指的是分区的属性值是由用户在加载数据的时候手动指定的。
语法如下:
load data [local] inpath 'filepath ' into table tablename partition(分区字段='分区值'...);
Local参数用于指定待加载的数据是位于本地文件系统还是HDFS文件系统。关于load语句后续详细展开讲解。
静态加载数据操作如下,文件都位于Hive服务器所在机器本地文件系统上(node1)。
load data local inpath '/home/huser/partition/users_hubei.txt' into table users_par partition(sheng='hubei');
load data local inpath '/home/huser/partition/users_henan.txt' into table users_par partition(sheng='henan');
load data local inpath '/home/huser/partition/users_hubei.txt' into table users_par partition(sheng='anhui');
外表上看起来分区表好像没多大变化,只不过多了一个分区字段。实际上分区表在底层管理数据的方式发生了改变。这里直接去HDFS查看区别。
现要求查询来自河南,年龄为18岁的人的信息,sql语句如下:
select count(*) from users_par where sheng=‘henan’ and age>18;
分区表的使用重点在于:
一、建表时根据业务场景设置合适的分区字段。比如日期、地域、类别等;
二、查询的时候尽量先使用where进行分区过滤,查询指定分区的数据,避免全表扫描。
通过建表语句中关于分区的相关语法可以发现,Hive支持多个分区字段: PARTITIONED BY (partition1 data_type, partition2 data_type,….)。
多重分区下,分区之间是一种递进关系,可以理解为在前一个分区的基础上继续分区。
从HDFS的角度来看就是文件夹下继续划分子文件夹。比如:把全国人口数据首先根据省进行分区,然后根据市进行划分,如果你需要甚至可以继续根据区县再划分,此时就是3分区表。
代码示例:
--单分区表,按省份分区
create table users_par(
id int,
name string,
age int,
province string,
city string
) partitioned by (sheng string)
row format delimited
fields terminated by “,";
--双分区表,按省份和市分区
create table users_par_sec(
id int,
name string,
age int,
province string,
city string
) partitioned by (sheng string, shi string)
row format delimited
fields terminated by “,";
--多分区表的数据插入和查询使用
load data local inpath ‘文件路径’ into table users_par partition(sheng=‘henan’);
load data local inpath ‘文件路径’ into table t_user_province_city partition(sheng=‘henan’,shi=‘xinyang’);
select * from users_par_sec where province='henan' and city= ' xinyang';
分桶表也叫做桶表,叫法源自建表语法中bucket单词,是一种用于优化查询而设计的表类型。
分桶表对应的数据文件在底层会被分解为若干个部分,通俗来说就是被拆分成若干个独立的小文件。
在分桶时,要指定根据哪个字段将数据分为几桶(几个部分)。
分桶规则如下:桶编号相同的数据会被分到同一个桶当中。
Bucket number = hash_function(bucketing_column) mod num_buckets
分桶编号 = 哈希方法(分桶字段) 取模 分桶个数
hash_function取决于分桶字段bucketing_column的类型:
如果是int类型,hash_function(int) == int;
如果是其他比如bigint,string或者复杂数据类型,hash_function比较棘手,将是从该类型派生的某个数字,比如hashcode值。
完整语法树所在位置:
CLUSTERED BY (col_name)表示根据哪个字段进行分;
INTO N BUCKETS表示分为几桶(也就是几个部分)。
需要注意的是,分桶的字段必须是表中已经存在的字段。
--分桶表建表语句
CREATE [EXTERNAL] TABLE table_name
[(col_name data_type, ...)]
CLUSTERED BY (col_name)
INTO N BUCKETS;
现有表users_cluster.txt记录了10个人的信息,要求建分桶表users_clu将改文件映射成数据表并分为3桶,字段为id、name、age、city。
根据city把数据分为3桶,建表语句如下:
CREATE TABLE users_clu(
id int,
name string,
age int,
city string
)CLUSTERED BY(city) INTO 3 BUCKETS
row format delimited
fields terminated by ',';
在创建分桶表时,还可以指定分桶内的数据排序规则:
CREATE TABLE users_clu_sort(
id int,
name string,
age int,
city string
)CLUSTERED BY(city)
Sorted by (id asc) INTO 3 BUCKETS
row format delimited
fields terminated by ',';
分桶表的数据加载
--将源数据上传到HDFS,users_clu表对应的路径下
hadoop fs -put users.txt /user/hive/warehouse/demo.db/users_clu
--step3:使用insert+select语法将数据加载到分桶表中
insert into users_clu select * from users_source;
到HDFS上查看users_clu底层数据结构可以发现,数据被分为了3个部分。
并且从结果可以发现,分桶字段一样的数据就一定被分到同一个桶中。
基于分桶字段查询时,减少全表扫描
--不再需要进行全表扫描过滤
--根据分桶的规则hash_function(hangzhou) mod 3计算出分桶编号
--查询指定分桶里面的数据 就可以找出结果 此时是分桶扫描而不是全表扫描
select * from users_clu where city=“hangzhou";
分桶表数据进行高效抽样
当数据量特别大时,对全体数据进行处理存在困难时,抽样就显得尤其重要了。抽样可以从被抽取的数据中估计和推断出整体的特性,是科学实验、质量检验、社会调查普遍采用的一种经济有效的工作和研究方法。
1.语法格式 ALTER TABLE table_name RENAME TO new_table_name;
2.Hive实例操作 hive(hivedwh)>alter table users rename users_new;
1.增加分区
(1)增加单个分区
hive(hivedwh)>alter table users_par add partition(province=‘hebei');
(2)同时增加多个分区,多个分区之间使用空格
hive(hivedwh)>alter table users_par add partition(province=‘hebei') partition(province=‘shanxi');
2.删除分区
(1)删除单个分区
hive(hivedwh)>alter table users_par drop partition (province=‘hebei');
(2)同时删除多个分区,多个分区之间使用逗号
hive(hivedwh)>alter table users_par drop partition(province=‘hebei'), partition(province=‘shanxi');
1.语法
修改列的语法格式:
ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]
增加和替换列的语法格式:
ALTER TABLE table_name ADD|REPLACE COLUMNS(col_name data_type [COMMENT col_comment], …)
关键字ADD表示新增一字段,字段位置在所有列后面(Partition列前);REPLACE则表示替换表中所有字段。
2.实例操作
(1)添加列
hive(hivedwh)>alter table users add columns(sex string);
(2)修改列
hive(hivedwh)>alter table users change column sex xingbie string;
(3)替换列
hive(hivedwh)>alter table users replace columns(id int, hight float, weight float);
Hive中的视图(view)是一种虚拟表,只保存定义,不实际存储数据。
通常从真实的物理表查询中创建生成视图,也可以从已经存在的视图上创建新视图。
创建视图时,将冻结视图的架构,如果删除或更改基础表,则视图将失败。
视图是用来简化操作的,不缓冲记录,也没有提高查询性能。
--hive中有一张真实的基础表users
select * from users;
--1、创建视图
create view v_users as select id,name,city from users limit 3;
--能否从已有的视图中创建视图呢 可以的
create view v_users_view as select * from v_users limit 2;
--2、显示当前已有的视图show tables;
show views;--hive v2.2.0之后支持
--3、视图的查询使用
select * from v_users;
--能否插入数据到视图中呢?
--不行 报错 SemanticException:A view cannot be used as target table for LOAD or INSERT
insert into v_users select count_date,county,state,deaths from users;
--4、查看视图定义
show create table users;
--5、删除视图
drop view v_users_view;
--6、更改视图属性
alter view v_users set TBLPROPERTIES ('comment' = 'This is a view');
--7、更改视图定义
alter view v_users as select name, city from users limit 2;
将真实表中特定的列数据提供给用户,保护数据隐式
--通过视图来限制数据访问可以用来保护信息不被随意查询:
create table userinfo(firstname string, lastname string, ssn string, password string);
create view safer_user_info as select firstname, lastname from userinfo;
--可以通过where子句限制数据访问,比如,提供一个员工表视图,只暴露来自特定部门的员工信息:
create table employee(firstname string, lastname string, ssn string, password string, department string);
create view techops_employee as select firstname, lastname, ssn from userinfo where department = 'java';
降低查询的复杂度,优化查询语句
示例代码:
--使用视图优化嵌套查询
from (
select * from people join cart
on(cart.pepople_id = people.id) where firstname = 'join'
)a select a.lastname where a.id = 3;
--把嵌套子查询变成一个视图
create view shorter_join as
select * from people join cart
on (cart.pepople_id = people.id) where firstname = 'join';
--基于视图查询
select lastname from shorter_join where id = 3;