李翔-大数据技术

Big data technology!

第一章 Hive数据定义语言(DDL)-2025版


一、学习内容框架

image-20250303100135183



大数据技术解决两个问题:

1.海量数据的存储:Hadoop的HDFS

2.海量数据的计算:Hadoop的Mapreduce


存在的问题:数据存放在hdfs上,怎么去读取和写入?

而且Mapreduce编程的非常的困难,怎么样让更多的人使用大数据去计算与分析?

Hive【数据仓库】解决上面的两个问题:

:使用Hive把数据存储在Hdfs上,编写Sql【Hql】就可以在hdfs上进行数据的存储与计算查询


image-20250303100726106


1.1 什么是Hive

Apache Hive是一款建立在Hadoop之上的开源数据仓库系统,可以将存储在Hadoop文件中的结构化数据映射为一张数据库表,提供了类似SQL的查询模型,称为Hive查询语言(HQL),用于访问和分析存储在Hadoop文件中的大型数据集。

Hive核心是将HQL转换为MapReduce程序,然后将程序提交到Hadoop群集执行,就可以在hdfs上进行数据的在存储与计算了。


2.2 启动Hive的环境

# 以下的操作全在master上操作

# 启动hdfs
start-dfs.sh

# 启动yarn
start-yarn.sh

# 启动hive的元数据服务
hive --service metastore &

# 启动Hive的远程访问服务
hive --service hiveserver2 &

# 在master上操作
beeline -u jdbc:hive2://master:10000 -n root


2.3启动Hive的控制端

1.第一代客户端【不推荐】

hive



2.beeline客户端 【第二代的最新客户端,其实就是远程访问登录】

# 在master上操作
beeline -u jdbc:hive2://master:10000 -n root

# 如果master节点出现以下日志,表示hive启动成功
Beeline version 2.3.4 by Apache Hive
0: jdbc:hive2://master:10000>


3.使用IDEA做为客户端

配置IDEA

  • 打开IDEA,创建项目

    image-20250303120243501


    image-20250303120648546


配置hive驱动

方法:将hive-jdbc-jar包配置到IDEA中

步骤:打开 右侧Database 窗口

image-20250303125432639

创建 Driver

步骤:选中 Driver ,并点击

image-20230321185304287


image-20230321190439171


下载 Driver 所需依赖 1.去自己的主机上/opt/apps/hive/jdbc 目录中下载hive-jdbc-3.1.2-standalone.jar的 jar 包

注意:默认下载到电脑的桌面上的fsdownload文件夹

image-20250303121920504


2.把hive-jdbc-3.1.2-standalone.jar复制到IDEA中,并连接

在IDEA中粘贴jar包

image-20230321190550847


image-20230321190800109


image-20250303122211397


3.在IDEA中连接jar包

image-20250303122518263

如下图所示

image-20250303122817252


4.开启连接

选择下图的4,创建数据源,选择Create Data Source

image-20250303122736142

连接

image-20250303123507538


创建文件,并执行SQL语句

本例中文件取名为hive.sql

img


创建会话窗口

image-20250303124307094

image-20250303124344095

执行show databases命令进行测试

image-20250303124515103

或者右侧选择命令执行

img


运行结果:

image-20230103185819246


常见命令解释

img



二、Hive的DDL语言

1.1 创建数据库

示例1:创建一个数据库:itheima

create database if not exists itheima ;


【重点归纳】

  1. Hive数据库与HDFS目录:Hive在创建数据库时会在HDFS的/user/hive/warehouse目录下创建相应的文件夹来存储该数据库的表数据;如果只是删除HDFS上的数据库目录并不会影响Hive的元数据。

    192.168.36.100:9870

    image-20250304110514153

  2. 删除和重新创建数据库:Hive的元数据和HDFS的物理存储是分开的,因此在HDFS中删除数据库目录后,Hive元数据仍认为数据库存在,导致无法用同名重新创建数据库,而且使用Show databases还能看到数据库存在。

  3. 如果要完全删除Hive数据库:需使用DROP DATABASE 数据库名 CASCADE命令,同时清理元数据和物理存储。避免在HDFS上直接删除数据库的目录


示例2:创建数据库itcast,并将其数据存储在 HDFS的 /hive_db/create_db/itcast.db 目录中。

CREATE DATABASE IF NOT EXISTS itcast
LOCATION '/hive_db/create_db/itcast.db'

-- 注意:在hive中不能创建有同名的数据库,如果创建不成功,检查一下hive中是否有同名的数据库


使用默认 LOCATION 时的行为:

  • 当未指定 LOCATION,Hive 会使用默认的数据仓库路径(通常是 /user/hive/warehouse),并通常会在这个路径下立即创建一个以数据库名命名的目录。



1.2 查看数据库

Hive中查询数据库的语法格式如下:

SHOW DATABASES [LIKE  '数据库名'];

-- 字段说明:
[ ]表示可选字段
show databases 显示所有数据库
LIKE  '数据库名' 可选,LIKE子句用于模糊查询,[可以使用通配符]
_代表任意一个字符
%代表任意字符
-- 示例1
-- 查询Hive中所有数据库
SHOW DATABASES

-- 查询Hive中数据库名称首字母是“i”的数据库。
SHOW DATABASES LIKE 'i*'

有一个例外就是default数据库中的表,default数据库没有自己的目录,所以是直接放在/user/hive/warehouse下面的


1.3 查询数据库的信息

Hive中的DESCRIBE DATABASE语句用于显示Hive中数据库的名称、注释(如果已设置)及其在文件系统上的位置等信息。

DESC DATABASE [EXTENDED] db_name;
-- EXTENDED:用于显示更多信息
-- 查询Hive数据库itcast的信息
DESC DATABASE itheima;

-- 查询Hive数据库itcast的详细信息(除了基础信息外,还显示如数据库的元数据、创建时间和其他数据库属性。)
DESC DATABASE EXTENDED itheima;


1.4 选择数据库

Hive中的USE DATABASE语句用于选择特定的数据库,切换当前会话使用哪一个数据库进行操作。

-- 语法: USE database_name;

-- 将当前使用的数据库切换至数据库itcast
USE itcast;

-- 查看当前所在的数据库
select  current_database();


1.5 删除数据库

Hive中的DROP DATABASE语句用于删除(删除)数据库。

默认行为是RESTRICT,这意味着仅在数据库为空时才删除它。要删除带有表的数据库,我们可以使用CASCADE

DROP DATABASE IF EXISTS database_name CASCADE;

-- DROP (DATABASE|SCHEMA):表示删除数据库的语句;
-- IF EXISTS:可选,用于判断数据库是否存在;
-- database_name:用于指定数据库名称;
-- CASCADE:可选,表示数据库中存在表时也强制删除数据库。


案例—王者荣耀

文件archer.txt中记录了手游《王者荣耀》射手的相关信息,内容如下所示,其中字段之间分隔符为制表符\t,要求在Hive中建表映射成功该文件。

1. 在master的路径 /opt下创建data目录

mkdir -p /opt/data

2.创建archer.txt文件,并上传到/opt/data目录下

1 后羿 5986 1784 396 336 remotely archer
2 马可波罗 5584 200 362 344 remotely archer
3 鲁班七号 5989 1756 400 323 remotely archer
4 李元芳 5725 1770 396 340 remotely archer
5 孙尚香 6014 1756 411 346 remotely archer
6 黄忠 5898 1784 403 319 remotely archer
7 狄仁杰 5710 1770 376 338 remotely archer
8 虞姬 5669 1770 407 329 remotely archer
9 成吉思汗 5799 1742 394 329 remotely archer
10 百里守约 5611 1784 410 329 remotely archer assassin

字段含义:

id、name(英雄名称)、hp_max(最大生命)、mp_max(最大法力)、attack_max(最高物攻)、defense_max(最大物防)、attack_range(攻击范围)、role_main(主要定位)、role_assist(次要定位)。

分析一下:字段都是基本类型,字段的顺序需要注意一下。字段之间的分隔符是制表符,需要使用row format语法进行指定。


3. 创建数据库与数据表

-- 打开IDEA,连接Hive

-- 删除数据库
drop database if exists honor_of_kings cascade;

-- 创建数据库并切换使用
create database if not exists honor_of_kings;

-- 选择数据库
use honor_of_kings;

-- 查看当前数据库
select current_database();

-- 创建数据表
create table if not exists honor_of_kings.t_archer(
    id int comment "ID",
    name string comment "英雄名称",
    hp_max int comment "最大生命",
    mp_max int comment "最大法力",
    attack_max int comment "最高物攻",
    defense_max int comment "最大物防",
    attack_range string comment "攻击范围",
    role_main string comment "主要定位",
    role_assist string comment "次要定位"
)
row format delimited 
fields terminated by "\t"
STORED AS TEXTFILE;

-- 查看数据表的内容
select * from t_archer;

--  查看数据表的信息
desc extended t_archer;

-- 查看数据表详细信息【元数据】
desc formatted t_archer;


4.archer.txt文件上传到t_archer表文件夹下。

-- 上传本地数据到hive的表(其实就是在hdfs中,hive把数据表是映射在了HDFS)
-- 语法:hdfs dfs -put 本地文件 hdfs的路径 

-- 4.1 上传本地数据到hive的表
LOAD DATA LOCAL INPATH '/opt/data/archer.txt' INTO TABLE honor_of_kings.t_archer;

-- 4.2 在HDFS的web UI 去查看数据是否上传到了t_archer目录中
master:9870

-- 4.3 在master上使用hdfs dfs命令查看数据
hdfs dfs -ls -R /

-- 4.4 在master的主机上运行命令查看数据
hdfs dfs -cat /user/hive/warehouse/honor_of_kings.db/t_archer/*


5.在IDEA执行SQL查询操作,可以看出数据已经映射成功。

select  * from t_archer;

img


想一想:Hive这种能力是不是比mysql一条一条insert插入数据方便多了?


三、Hive DDL建表高阶

1. Hive内、外部表

1.1 什么是内部表

Hive内部表,也叫管理表,创建表时默认创建的就是内部表。Hive对内部表拥有完全的控制权,包括数据和表结构的管理。

存储与管理

  • 存储位置:内部表的数据存储在Hadoop分布式文件系统(HDFS)的指定目录中。

  • 数据格式:数据以Hadoop的文件格式存储,确保与Hadoop生态系统的兼容性。

  • 数据管理Hive完全管理内部表的数据。这包括数据的添加、删除和修改等操作。用户通过Hive提供的命令进行这些操作,而无需直接操作底层HDFS。

数据操作

  • 数据检索:使用Hive的SELECT语句可以从内部表中查询数据。Hive负责从HDFS读取数据并返回查询结果。

  • 数据维护:与外部表相比,用户可以通过Hive命令直接对表中的数据进行修改、添加或删除。

生命周期

  • 创建与删除当删除内部表时,Hive不仅删除表的元数据,还删除存储在HDFS上的源数据。这是内部表与外部表的关键区别,外部表删除时不会删除数据。

基本操作

  • 创建数据库

drop database if exists hive_test;

create database if not exists hive_test;
  • 选择数据库

use hive_test;
  • 创建内部表student

create table student(
    num int,
    name string,
    sex string,
    age int,
    dept string) 
row format delimited 
fields terminated by ',';
  • 查看student表的元数据描述信息

DESC FORMATTED student;

image-20230418175055247


1.2 什么是外部表

Hive外部表允许定义表结构,但不管理数据本身。这些表使用EXTERNAL关键字创建,主要用于访问存储在HDFS或其他外部存储系统中的数据。Hive负责管理外部表的元数据,而数据的实际存储和管理由外部系统处理。

存储与管理

  • 存储位置:外部表的数据存储在指定的外部位置,可以是HDFS或其他外部存储系统。

  • 数据格式:数据的格式由存储在外部系统中的实际数据决定,Hive适应这些格式以正确解析数据。

  • 数据管理数据的管理(添加、删除和修改)由外部存储系统负责,Hive不对外部表中的数据进行管理

数据操作

  • 数据检索:使用Hive的SELECT语句可以查询外部表数据,Hive从外部存储系统读取并返回数据。

  • 数据维护与内部表不同,Hive不能直接对外部表中的数据进行修改、添加或删除操作。数据维护必须通过外部存储系统进行。

生命周期

  • 创建:创建外部表时,使用LOCATION参数指定数据的存储位置。Hive初始化表结构的元数据,而不影响实际数据。

  • 删除删除外部表仅移除Hive中的元数据,实际存储在外部系统的数据保持不变,仍可在Hive之外访问。


基本操作

  • 创建外部表student_ext

create external table student_ext(
    num int,
    name string,
    sex string,
    age int,
    dept string)
row format delimited
fields terminated by ','
location '/stu';

备注:外部表本身只是在Hive中定义的一个表结构,它并不包含任何实际的数据。只有在外部表所指定的HDFS路径下放置了相应的数据文件后,才能通过HDFS Web UI来查看这些文件。

查看student_ext表的元数据描述信息

DESC FORMATTED student_ext;

image-20230418180952586


1.3 案例演示

下面我们将用一个关于NBA球员分析的数据进行区别内部表和外部表。

-- 删除数据库
drop database if exists nba;

-- 创建数据库nba
create database if not exists nba;

-- 选择数据库
use nba;

-- 检查目前所在的数据库
select current_database();

1.创建内部表t1

-- 删除内部表t1
drop table if exists t1;

-- 创建内部表t1
create table if not exists t1(
    name string comment '名字',
    pos string comment '位置',
    height double comment '身高',
    weight int comment '体重',
    age int comment '年龄',
    nba_age int comment '球龄',
    nums int comment '出场次数',
    avgtime double comment '平均时间',
    attack double comment '进攻能力',
    defend int comment '防守能力',
    allstar string comment '是否进入全明星',
    income bigint comment '薪资'
) comment "NBA球员分析"
row format delimited
fields terminated by ',';
 
-- 查看表t1的元数据信息
desc formatted t1;

image-20250307132853700

type标明MANAGED_TABLE说明这个表是受监管的。也就是内部表。


2.创建外部表t2

-- 删除外部表t2
drop table if exists t2;

-- 创建外部表t2
create external table t2(
    name string comment '名字',
    pos string comment '位置',
    height double comment '身高',
    weight int comment '体重',
    age int comment '年龄',
    nba_age int comment '球龄',
    nums int comment '出场次数',
    avgtime double comment '平均时间',
    attack double comment '进攻能力',
    defend int comment '防守能力',
    allstar string comment '是否进入全明星',
    income bigint comment '薪资'
) comment "NBA球员分析"
row format delimited
fields terminated by ',';
 
-- 查看表结构
desc formatted t2;

image-20250307133000425

type标明EXTERNAL_TABLE说明这个表是外部表。


3. 将数据导入到两个表之间然后删除

nba.txt可以在excel中制作,导出为带逗号分隔的csv文件,然后使用notepad++转换一下格式,否则在idea下运行脚本会出现中文乱码。 转换方法:notepad++ --> 编辑 --> 档案格式转换 --> 转为unix

-- 上传数据nba.txt到master节点的 /opt/data目录中

-- 数据载入t1,t2  【local表示从本地加载】
load data local inpath '/opt/data/nba.txt' into table t1;  
load data local inpath '/opt/data/nba.txt' into table t2;

-- 查看数据表
select * from t1;
select * from t2;

image-20230104180838047


4. 查看HDFS端口9870:删除前

image-20230104181115216

image-20230104181135836


5.查看HDFS上存放的数据

[root@master ~]# hdfs dfs -cat /user/hive/warehouse/nba.db/t1/*

[root@master ~]# hdfs dfs -cat /user/hive/warehouse/nba.db/t2/*


6. 删除t1和t2表

drop table if exists t1;

drop table if exists t2;


查看删除后的结果:

image-20230104181414098


HDFS上只有t2的数据还在,但是它的元数据已被删除,这里显示表找不到。

image-20230104181527124


数据表t1是内部表:故删除表时,数据也会被删除(适用于Hive完全管理的数据)。

数据表t2是外部表:故删除表时,仅删除元数据,数据仍然存在(适用于已有数据或共享数据)。



1.4 内部表、外部表差异

无论内部表还是外部表,Hive都在Hive Metastore中管理表定义及其分区信息。

  • 删除内部表,会从Metastore中删除表元数据,还会从HDFS中删除其所有数据/文件。

  • 删除外部表,只会从Metastore中删除表的元数据,并保持HDFS位置中的实际数据不变。

实验结论

表类型数据存放位置删除表时数据是否删除适用场景
内部表 (Managed Table)/user/hive/warehouse/数据库名.db/表名/数据和表都会删除Hive全权管理的表,适用于ETL
外部表 (External Table)用户指定的HDFS路径仅删除表的元数据,数据仍然保留适用于已有数据或多个工具共享

重点总结

  1. 内部表:Hive完全管理,删除表时数据也删除。

  2. 外部表:用户管理数据,删除表时数据不会删除。


1.5 内部表、外部表的创建实验

当需要通过Hive完全管理控制表的整个生命周期时,请使用内部表。

当文件已经存在或位于远程位置时,请使用外部表,因为即使删除表,文件也会被保留。

准备数据

在/opt/data目录下准备数据,创建dept.txt文件并添加数据:

[root@master data]# vim dept.txt

100,数学系,2100
200,物理系,2200
300,化学系,2300
400,新闻系,2400
500,软件系,2500
练习1:内部表创建
/* 创建内部表 */
--(1)启动Hive
-- 复制dept.txt到master节点下的/opt/data目录下

--(2)显示数据仓库
show databases;

--(3)创建一个名为hivedwh的数据仓库,并存放在默认位置:
drop database if exists hivedwh cascade;
create database if not exists hivedwh;

--(4)切换到hivedwh数据仓库
use hivedwh;
select current_database();

--(5)创建内部表dept_int
create table if not exists dept_int(
        deptno int,
        dname string,
        buildingsno int)
row format delimited
fields terminated by ',';

--(6)查看创建的表
show tables;

--(7)向内部表中导入数据
load data local inpath '/opt/data/dept.txt' into table dept_int;

--(8)简单查询
select * from dept_int;

--(9)查看表的元数据信息
desc formatted dept_int;

-- (10)master主机上运行HDFS命令查看HDFS上的数据
/*
[root@master ~]# hdfs dfs -ls -R /user/hive/warehouse/hivedwh.db/
[root@master ~]# hdfs dfs -cat /user/hive/warehouse/hivedwh.db/dept_int/dept.txt
*/

-- (11)删除数据表dept
drop table if exists dept_int;
-- 查看数据表【发现dept表已经不存在】
show tables ;
-- 在HDFS上查看dept数据表【目录】已不存在,因为是内部表,所以元数据和数据都被删除


练习2:外部表创建
/* 创建外部表 */

--(1)创建外部表dept_ext
create external table if not exists dept_ext(
    deptno int,
    dname string,
    buildingsno int)
row format delimited
fields terminated by ',';

--(2)查看创建的表
show tables;

--(3)向外部表中导入数据
load data local inpath '/opt/data/dept.txt' into table dept_ext;

--(4)简单查询
select * from dept_ext;

--(5)查看表的元数据信息
desc formatted dept_ext;

--(6)在master主机上运行HDFS命令查看HDFS上的数据
/*
[root@master ~]# hdfs dfs -ls -R /user/hive/warehouse/hivedwh.db/
[root@master ~]# hdfs dfs -cat /user/hive/warehouse/hivedwh.db/dept_ext/dept.txt
*/

--(7)删除数据表dept
drop table if exists dept_ext;
-- 查看数据表【发现dept表已经不存在】
show tables ;
-- 在HDFS上查看dept数据表【目录】仍然存在,因为是外部表,所以没有被删除


在创建Hive外部表时,定义的字段与dept.txt中的数据有几个关键性的关系和要求:

  1. 数据类型匹配:在创建表时定义的字段类型必须与dept.txt中相应数据的实际类型相匹配。例如,如果dept.txt中的deptno是整数,那么在Hive表中deptno字段应定义为INT类型。

  2. 列的顺序:Hive表中字段的顺序应与dept.txt数据文件中每行数据的列的顺序一致。

  3. 列的数量:Hive表定义中的字段数量应该与dept.txt数据文件中每行的列数相匹配。如果数据文件中的列比Hive表中定义的字段多,那么多出的列将被忽略。如果数据文件中的列比Hive表中定义的字段少,那么缺失的列将被视为null。

  4. 字段分隔符:Hive表定义中指定的字段分隔符(如上例中的空格'\t')必须与dept.txt数据文件中实际使用的字段分隔符相匹配。如果分隔符不匹配,Hive将无法正确解析字段。


1.6 向Hive表中添加数据的方法

在Hive中,有两种主流的数据添加方法:LOAD DATAhdfs dfs -put。这两种方法有以下主要区别:

1. 语法差异:

  • LOAD DATA命令:

    • LOCAL这是一个可选关键字,用于指定加载的数据文件位于本地文件系统。如果没有指定LOCAL,那么默认情况下Hive会从HDFS上加载数据。

    • INPATH 'filepath':这里的'filepath'需要替换为您的数据文件路径。这个路径应该是完整的路径,指向包含要加载数据的文件。如果使用LOCAL关键字,这个路径应该是本地文件系统的路径;如果没有使用LOCAL,则应该是HDFS的路径。

    • [OVERWRITE]:这也是一个可选关键字。如果指定了OVERWRITE,Hive会在加载数据前删除表中现有的所有数据。如果不使用OVERWRITE,新数据将会被追加到表中,不会影响表中现有的数据。

    • INTO TABLE tablename:这里的tablename是目标Hive表的名称,即您希望将数据加载到哪个表中

    • 作用:将数据从文件系统(本地或HDFS)直接加载到Hive表中。

    • 语法:LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename

  • HDFS DFS -PUT命令:

    • /path/to/localfile.txt为本地文件路径。

    • /path/on/hdfs/为HDFS目标路径。

    • 用于上传文件到HDFS。

    • 语法:hdfs dfs -put /path/to/localfile.txt /path/on/hdfs/

2. 使用场景:

  • LOAD DATA 主要用于从本地文件系统或HDFS向Hive表加载数据。

  • HDFS DFS -PUT 主要用于将本地文件上传到HDFS。

3. 性能和可扩展性:

  • LOAD DATA

    • 支持自动并行加载,利用MapReduce框架。

    • 根据表的分区和分桶设置自动调整并行度和资源分配。

    • 适用于高效地加载数据到Hive表。

  • HDFS DFS -PUT

    • 不支持在Hive自动并行加载。

    • 需要手动并行上传或使用其他工具。

    • 更适合于简单的数据文件上传到HDFS。

根据需求和数据量大小选择合适的方法对于提高效率至关重要。LOAD DATA命令适合高效地将数据加载到Hive表中,而HDFS DFS -PUT命令更适合于上传文件到HDFS。


HDFS dfs -put怎么才能向Hive表中传输数据?

步骤:先本地导入数据,然后创建外部表关联

  • 创建外部表,并指定加载数据的HDFS的路径。

    # 创建外部表
    CREATE EXTERNAL TABLE IF NOT EXISTS dept_ext_put(
        deptno INT,
        dname STRING,
        buildingsno INT
    )
    ROW FORMAT DELIMITED 
    FIELDS TERMINATED BY ','
    LOCATION '/user/hive/warehouse/hivedwh.db/dept_ext_put';
    
    
    # 注意:此时/user/hive/warehouse/hivedwh.db/dept_ext2/路径下并没有dept.txt文件
    Hive 外部表的数据是存储在 HDFS 或其他支持的文件系统中,而不是由 Hive 直接管理。
    这意味着,您可以在任何时间点将数据文件放入外部表指定的位置,Hive 会在查询时读取这个位置的数据。
  • 使用HDFS DFS -PUT命令把表上传到建表时指定的HDFS的路径

    [root@master ~]#  hdfs dfs -put /opt/data/dept.txt /user/hive/warehouse/hivedwh.db/dept_ext_put/


2. Hive分区表

img


Hive 分区的核心概念与实践指南:

  1. 什么是 Hive 分区?

    • 在 Hive 中,分区是一种将大数据集分割为更小、更易管理的数据集的策略。这种分割是通过创建不同的目录来实现的,每个目录代表一个数据集的子集。

  2. 分区表的物理存储:

    • 物理上,每个 Hive 分区表对应 HDFS 上的一个特定目录。

    • 这个目录包含了属于该分区的所有数据文件。

    • 在 Hive 的结构中,意味着每个分区都与表下的一个子目录相对应,且该子目录内包含了所有分区数据。

    • sales_partitioned/
          └── 2023-01/
          │     ├── data_file_1.csv
          │     └── data_file_2.csv
          ├── 2023-02/
          │     ├── data_file_3.csv
          │     └── data_file_4.csv
          ├── 2023-03/
          │     ├── data_file_5.csv
          │     └── data_file_6.csv
          └── ...
  3. 分区字段的角色:

    • 分区字段不是表中的真实数据字段,它只是用于管理数据的“标识”。

    • 分区字段的值不会存储在数据文件中,而是体现在文件路径上。


  4. 为什么要使用分区表?

    • 提高查询效率:查询时只扫描相关分区,而不是整张表。

    • 减少数据扫描:分区裁剪让 Hive 跳过无关数据,加快查询速度。

    • 管理更方便:数据按时间、地区等分类,结构清晰,易维护。

    • 优化存储:分区减少单个文件大小,提高 HDFS 读写性能。

    • 支持并行处理:不同分区的数据可分布存储,提升计算速度。


2.1 分区表的引入、产生背景

现有6份数据文件,分别记录了《王者荣耀》中6种位置的英雄相关信息。

要求:建立数据表t_all_hero,把6份文件同时映射加载。

-- 任务
-- 删除数据库
drop database if exists honor_of_kings cascade ;

-- 创建数据库
create database if not exists honor_of_kings;

-- 选择数据库
use honor_of_kings;

-- 查看当前数据库
select current_database();

-- 创建数据表
create table if not exists t_all_hero(
   id int,
   name string,
   hp_max int,
   mp_max int,
   attack_max int,
   defense_max int,
   attack_range string,
   role_main string,
   role_assist string
)
   row format delimited
   fields terminated by "\t";
        
-- 查看数据表
show tables ;
        
-- 上传6个数据文件到master:/opt/data

-- 加载数据到数据表
LOAD DATA LOCAL INPATH '/opt/data/archer.txt' INTO TABLE t_all_hero;
LOAD DATA LOCAL INPATH '/opt/data/assassin.txt' INTO TABLE t_all_hero;
LOAD DATA LOCAL INPATH '/opt/data/mage.txt' INTO TABLE t_all_hero;
LOAD DATA LOCAL INPATH '/opt/data/support.txt' INTO TABLE t_all_hero;
LOAD DATA LOCAL INPATH '/opt/data/tank.txt' INTO TABLE t_all_hero;
LOAD DATA LOCAL INPATH '/opt/data/warrior.txt' INTO TABLE t_all_hero;

查看HDFS 的web UI

img

-- 全表查询
select * from t_all_hero;

-- 查询role_main主要定位是射手archer并且hp_max最大生命大于6000的数量
select count(*) from t_all_hero where role_main='archer' and hp_max>6000;

image-20230104192203840

思考一下:where语句的背后需要进行全表扫描才能过滤出结果,对于hive来说需要扫描表下面的每一个文件。如果数据文件特别多的话,效率很慢也没必要。本需求中,只需要扫描archer.txt文件即可,如何优化可以加快查询,减少全表扫描呢?


2.2 分区表的概念、创建

当Hive表对应的数据量大、文件多时,为了避免查询时全表扫描数据,Hive支持根据用户指定的字段进行分区,分区的字段可以是日期、地域、种类等具有标识意义的字段。比如把一整年的数据根据月份划分12个月(12个分区),后续就可以查询指定月份分区的数据,尽可能避免了全表扫描查询。

img

分区表建表语法

CREATE TABLE table_name (
 column1 data_type, column2 data_type) 
 PARTITIONED BY (partition1 data_type, partition2 data_type,......);


需求:以role角色作为分区字段创建静态分区表和动态分区表

针对《王者荣耀》英雄数据,重新创建一张分区表t_all_hero_part,以role角色作为分区字段。

# 创建分区表
create table t_all_hero_part(
       id int,
       name string,
       hp_max int,
       mp_max int,
       attack_max int,
       defense_max int,
       attack_range string,
       role_main string,
       role_assist string
) partitioned by (role string)
row format delimited
fields terminated by "\t";

注意:

分区字段不能与表中的普通字段同名,否则会导致表结构冲突

分区字段本身不会存储在数据文件中,但在查询时,它们会作为虚拟字段出现在表结构中。

img


2.3 分区表数据加载--静态分区

所谓静态分区是在创建表时就已经定义好的分区,插入数据时需要显式指定分区的值。

语法如下:

load data [local] inpath '文件路径' into table tablename partition(分区字段='分区值'...);
  • "local": 可选参数,表示从本地文件系统加载数据,如果省略该参数,则表示从 HDFS 加载数据。

  • "inpath": 必选参数,指定待加载数据的路径,可以是本地文件系统路径或 HDFS 路径。

  • "into table tablename": 必选参数,指定要将数据加载到的目标表名。

  • "partition(分区字段='分区值'...)": 可选参数,表示将数据加载到表的特定分区中,如果省略该参数,则表示将数据加载到表的非分区部分。

静态加载数据操作如下:把以下数据文件都上传到本地文件系统上/opt/data目录下

[root@master data]# pwd
/opt/data

[root@master data]# ll
总用量 44
-rw-r--r--. 1 root root  480 1月   4 12:37 archer.txt
-rw-r--r--. 1 root root  292 1月   4 19:15 assassin.txt
-rw-r--r--. 1 root root  437 1月   4 13:00 hot_hero_skin_price.txt
-rw-r--r--. 1 root root 4237 1月   4 19:49 log.txt
-rw-r--r--. 1 root root  883 1月   4 19:15 mage.txt
-rw-r--r--. 1 root root 1276 1月   4 17:32 nba.txt
-rw-r--r--. 1 root root  289 1月   4 19:15 support.txt
-rw-r--r--. 1 root root  446 1月   4 19:15 tank.txt
-rw-r--r--. 1 root root  207 1月   4 13:31 team_ace_player.txt
-rw-r--r--. 1 root root  837 1月   4 19:15 warrior.txt

静态加载数据

-- 将本地路径为 '/opt/data/archer.txt' 的数据
-- 加载到Hdfs上名为 t_all_hero_part 的表中的 'sheshou' 分区中。
-- 注意:不建议使用中文做分区键
load data local inpath '/opt/data/archer.txt' 
 into table t_all_hero_part partition(role='sheshou');

-- 同理
load data local inpath '/opt/data/assassin.txt' 
 into table t_all_hero_part partition(role='cike');

load data local inpath '/opt/data/mage.txt' 
 into table t_all_hero_part partition(role='fashi');

load data local inpath '/opt/data/support.txt' 
 into table t_all_hero_part partition(role='fuzhu');

load data local inpath '/opt/data/tank.txt' 
 into table t_all_hero_part partition(role='tanke');

load data local inpath '/opt/data/warrior.txt' 
 into table t_all_hero_part partition(role='zhanshi');


# -- 在分区表中查询role_main主要定位是射手archer并且hp_max最大生命大于6000的数量
select count(*) from t_all_hero_part where role_main='archer' and hp_max>6000;
# 在master中使用hdfs命令查看分区表里的内容
hdfs dfs -cat /user/hive/warehouse/honor_of_kings.db/t_all_hero_part/role=sheshou/*


查看WEB端的HDFS

image-20230104204135118

查看表内容

-- 使用select查看数据表
select * from t_all_hero_part;

image-20230104204253058

-- 使用select查看数据表中tanke的数据信息
select *
from t_all_hero_part
where role='tanke';

image-20230426131144213


2.4 分区表数据加载--动态分区

动态分区基础

  • 动态分区定义:在数据加载时,Hive 自动根据数据的值创建相应的分区,无需手动指定,提升管理效率。

  • 核心实现语法:使用 INSERT ... SELECT 语句,其中 最后一列的值作为分区字段,Hive 会自动创建并分配数据到相应的分区。

启用和配置动态分区

在使用动态分区之前,必须在Hive会话中设置以下两个参数:

set hive.exec.dynamic.partition=true;  # 启用动态分区
set hive.exec.dynamic.partition.mode=nonstrict;  # 设置为非严格模式
或者 set hive.exec.dynamic.partition.mode=strict;  # 设置为严格模式

动态分区模式

  • 非严格模式(nonstrict mode):允许所有分区键动态生成,无需静态指定任何分区键。

  • 严格模式(strict mode):要求 INSERT 语句至少有一个分区键静态指定,防止生成过多分区影响性能。

分区列指定方法

  • 1.直接使用列名:当源表和目标表的分区字段名称相同时,可直接使用列名,无需额外处理。

    set hive.exec.dynamic.partition=true;  # 启用动态分区
    set hive.exec.dynamic.partition.mode=nonstrict;  # 设置为非严格模式
    
    INSERT INTO TABLE table_name PARTITION (partition_column)
    SELECT column1, column2, ..., partition_column
    FROM source_table;
  • 2.使用 as 进行重命名:当源表和目标表的分区字段名称不同时,需要使用 AS 进行重命名,确保数据正确分配到目标分区。

    set hive.exec.dynamic.partition=true;  # 启用动态分区
    set hive.exec.dynamic.partition.mode=nonstrict;  # 设置为非严格模式
    
    INSERT INTO TABLE table_name PARTITION (partition_column)
    SELECT column1, column2, ..., source_partition_column as partition_column
    FROM source_table;


严格模式下的动态分区

  • 在严格模式下,至少一个分区键需静态指定,这有助于防止创建过多分区,避免性能问题。

    set hive.exec.dynamic.partition=true;  # 启用动态分区
    set hive.exec.dynamic.partition.mode=strict;  # 设置为严格模式
    
    INSERT INTO TABLE table_name 
      PARTITION (year=2022, month)
    SELECT column1, column2, ..., month
      FROM source_table;

注意事项

  • 在非严格模式下,要注意不要创建大量无意义的分区,以免影响性能。

  • 生产环境建议使用严格模式,确保数据加载的稳定性和查询的准确性。

通过这种方式,我们提供了一个关于Hive动态分区全面且结构化的概览,旨在帮助用户更好地理解和实施动态分区,以提高数据处理效率和准确性。


动态分区实验

创建一张新的分区表

-- 启用动态分区
set hive.exec.dynamic.partition=true;
-- 设置为非严格模式
set hive.exec.dynamic.partition.mode=nonstrict;

-- 选择数据库
use honor_of_kings;

-- 删除数据表
drop table if  exists t_all_hero_part_dynamic;

-- 创建一张新的分区表t_all_hero_part_dynamic
create table t_all_hero_part_dynamic(
    id int,
    name string,
    hp_max int,
    mp_max int,
    attack_max int,
    defense_max int,
    attack_range string,
    role_main string,
    role_assist string
) partitioned by (role string)
    row format delimited
    fields terminated by "\t";

-- 查看表结构,会发现最后多了一个分区列role
select * from t_all_hero_part_dynamic;
  • partitioned by (role string) 不会在数据表中真正创建 role,而是role 作为分区字段,Hive 通过文件目录结构来管理该分区字段,而不是存储在数据文件中。

  • 分区字段是虚拟列,查询时可以像普通列一样使用,但它的值来自数据存储路径,而非数据文件本身。

  • 不能在表结构中重复定义分区列,否则会报 Column repeated in partitioning columns 错误。因为 分区字段不能与表中的普通字段重名,否则 Hive 无法区分它们的作用。


1.执行静态分区插入数据

insert into table t_all_hero_part_dynamic
partition(role='archer')
select * from t_all_hero where role_main = 'archer';

insert into table t_all_hero_part_dynamic
partition(role='assassin')
select * from t_all_hero where role_main = 'assassin';

insert into table t_all_hero_part_dynamic
partition(role='mage')
select * from t_all_hero where role_main = 'mage';

insert into table t_all_hero_part_dynamic
partition(role='support')
select * from t_all_hero where role_main = 'support';

insert into table t_all_hero_part_dynamic
partition(role='tank')
select * from t_all_hero where role_main = 'tank';

insert into table t_all_hero_part_dynamic
partition(role='warrior')
select * from t_all_hero where role_main = 'warrior';


2.执行动态分区插入数据

在 Hive 中,INSERT INTO ... PARTITION ... 是一种标准的语法

-- 确保 Hive 允许使用动态分区
SET hive.exec.dynamic.partition = true;      -- 启用动态分区
SET hive.exec.dynamic.partition.mode = nonstrict;  -- 设置为非严格模式(允许所有分区字段动态生成)

-- 将数据从 t_all_hero 表插入到 t_all_hero_part_dynamic 分区表中
INSERT INTO TABLE t_all_hero_part_dynamic
    PARTITION(role)        -- 指定 role 作为分区字段
SELECT 
    tmp.*,                 -- 选择源表 t_all_hero 的所有字段
    tmp.role_main AS role  -- 将 role_main 作为 role 分区字段插入
FROM t_all_hero tmp;       -- 从 t_all_hero 表获取数据
  • 其中:PARTITION(role) 指定了要插入数据的分区列【分区键】是 role,而分区列的值则是从 SELECT 语句中选择的列 role_main 中获取的。这种语法是固定的,并且在 Hive 中被广泛使用。

  • 动态分区插入时,分区值是根据查询返回字段位置自动推断的。


查看WEB端的HDFS

master:9870
192.168.36.100:9870

image-20230104205029638


# 查看表的全部信息内容
select * from t_all_hero_part_dynamic;

image-20230104205148669

-- 按条件查看archer数据
select * from t_all_hero_part_dynamic where role='archer'

image-20230426133439477


# 使用hdfs的命令行的方式查看
hdfs dfs -cat /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=archer/000000_0

image-20230426133635489


# 查看分区
show partitions t_all_hero_part;

image-20230426133603226


2.5 分区表的本质

Hive的分区表本质是将数据按照指定的列值进行物理上的分隔存储,以提高查询效率和管理数据的灵活性。

非分区表上看起来和分区表好像没多大变化,只不过多了一个分区字段。实际上在底层管理数据的方式发生了改变。这里直接去HDFS查看区别。

非分区表:t_all_hero

img

分区表:t_all_hero_part

img

img

分区的概念提供了一种将Hive表数据分离为多个文件/目录的方法。

不同分区对应着不同的文件夹,同一分区的数据存储在同一个文件夹下。只需要根据分区值找到对应的文件夹,扫描本分区下的文件即可,避免全表数据扫描。

[root@master data]# hdfs dfs -ls -R /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic

drwxr-xr-x   - root supergroup          0 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=archer
-rwxr-xr-x   3 root supergroup        499 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=archer/000000_0

drwxr-xr-x   - root supergroup          0 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=assassin
-rwxr-xr-x   3 root supergroup        297 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=assassin/000000_0

drwxr-xr-x   - root supergroup          0 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=mage
-rwxr-xr-x   3 root supergroup        902 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=mage/000000_0

drwxr-xr-x   - root supergroup          0 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=support
-rwxr-xr-x   3 root supergroup        294 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=support/000000_0

drwxr-xr-x   - root supergroup          0 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=tank
-rwxr-xr-x   3 root supergroup        453 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=tank/000000_0

drwxr-xr-x   - root supergroup          0 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=warrior
-rwxr-xr-x   3 root supergroup        845 2023-01-04 20:49 /user/hive/warehouse/honor_of_kings.db/t_all_hero_part_dynamic/role=warrior/000000_0


2.6 静态分区 vs. 动态分区

📌 分区方式
  • 静态分区:插入数据时,必须手动指定分区值,适用于已知分区值的情况。

  • 动态分区:分区值由数据自动生成,适用于分区值未知或数量较多的情况。

📌 分区表创建
  • 无论静态还是动态分区,建表语句相同,表结构相同,都需要指定分区字段(存储在 HDFS 目录)。

  • 区别在数据插入:静态分区手动指定,动态分区自动生成


2.7 分区列、分区键和分区值的区别

  1. 分区列 (Partition Column)

    • 定义:分区列是在创建带分区的Hive表时,在PARTITIONED BY子句中指定的列。

    • 作用:它们用于物理地组织表的数据。数据根据这些列的值被分割成不同的分区。

    • 例子:假设有一个按年(year)和月(month)分区的表,yearmonth就是分区列。

  2. 分区键 (Partition Key)

    • 定义:分区键通常指的是分区列的实际值,用于查询和管理数据时标识特定的分区。

    • 作用:在查询或数据操作时,分区键用于引用或定位特定的分区。

    • 例子:如果你在查询中指定WHERE year = 2022 AND month = 1,那么year = 2022month = 1就是分区键。

  3. 分区值 (Partition Value)

    • 定义:分区值指的是分区列的具体数值。它是数据在分区中如何被分隔和存储的基础。

    • 作用:分区值用于确定数据存储在哪个分区。在文件系统中,每个分区通常按照分区值命名,如目录year=2022/month=1

    • 例子:如果你有数据属于2022年1月,则这些数据的分区值是2022(对应于year分区列)和1(对应于month分区列)

小结

  • 分区列是表的结构的一部分,用于定义如何分区。

  • 分区键在查询或操作数据时使用,指向特定分区的分区列及其值。

  • 分区值是分区列在具体数据行或分区中的值,决定了数据的物理存储位置。

在实际使用中,分区键和分区值的概念经常交织在一起,因为分区键实际上是由分区列的分区值构成的。分区列则是定义这些值如何组织数据的结构元素。



2.8 分区表的使用

分区表的使用重点在于:

一、建表时根据业务场景设置合适的分区字段。比如日期、地域、类别等;

二、查询的时候尽量先使用where进行分区过滤,查询指定分区的数据,避免全表扫描。

比如:查询英雄主要定位是射手并且最大生命大于6000的个数。使用分区表查询和使用非分区表进行查询,SQL如下:

--非分区表 全表扫描过滤查询
select count(*) from t_all_hero where role_main="archer" and hp_max >6000;

--分区表 先基于分区过滤 再查询
select count(*) from t_all_hero_part where role="sheshou" and hp_max >6000;

想一想:底层执行性能来说,分区表的优势在哪里?


2.9 分区表的注意事项

一、 分区表不是建表的必要语法规则,是一种优化手段表,可选;

二、分区字段不能是表中已有的字段,不能重复;

三、 分区字段是虚拟字段,其数据并不存储在底层的文件中;

四、 分区字段值的确定来自于用户价值数据手动指定(静态分区)或者根据查询结果位置自动推断(动态分区

五、 Hive支持多重分区,也就是说在分区的基础上继续分区,划分更加细粒度


2.10 多重分区表

通过建表语句中关于分区的相关语法可以发现,Hive支持多个分区字段:PARTITIONED BY (partition1 data_type, partition2 data_type,….)

多重分区下,分区之间是一种递进关系,可以理解为在前一个分区的基础上继续分区。从HDFS的角度来看就是文件夹下继续划分子文件夹

比如:把全国人口数据首先根据省进行分区,然后根据市进行划分,再根据区县再划分,此时就是3分区表。

-- 单分区表,按省份分区
CREATE TABLE t_user_province (
    id INT, 
    name STRING,
    age INT
) 
PARTITIONED BY (province STRING)
ROW FORMAT DELIMITED 
FIELDS TERMINATED BY ',';  -- 指定逗号 `,` 作为字段分隔符

-- 双分区表,按省份和市分区
CREATE TABLE t_user_province_city (
    id INT, 
    name STRING,
    age INT
) 
PARTITIONED BY (province STRING, city STRING)
ROW FORMAT DELIMITED 
FIELDS TERMINATED BY ',';  -- 指定逗号 `,` 作为字段分隔符

-- 三分区表,按省份、市、县分区
CREATE TABLE t_user_province_city_county (
    id INT, 
    name STRING,
    age INT
) 
PARTITIONED BY (province STRING, city STRING, county STRING)
ROW FORMAT DELIMITED 
FIELDS TERMINATED BY ',';  -- 指定逗号 `,` 作为字段分隔符

多分区表的数据插入和查询使用

-- 加载数据到单分区表(按省份分区)
LOAD DATA LOCAL INPATH '/opt/data/t_user.csv' 
INTO TABLE t_user_province 
PARTITION(province='上海市');

-- 加载数据到多分区表(按省、市、区县分区)
LOAD DATA LOCAL INPATH '/opt/data/t_user.csv' 
INTO TABLE t_user_province_city_county 
PARTITION(province='浙江省', city='杭州市', county='萧山区');

-- 查询浙江省杭州市的数据
SELECT * FROM t_user_province_city_county 
WHERE province='浙江省' AND city='杭州市';


3. Hive分桶表

image-20240327171416490

3.1 业务场景

Hive分桶表

Hive 分桶(Bucketing) 是一种 数据存储优化技术,通过将数据按某列的哈希值均匀分布到多个桶(文件)中,提高查询效率。

📌 分区 vs. 分桶

  • 分区表:每个分区在 HDFS 上是一个目录(如 /year=2021/)。

  • 分桶表:在分区目录下,数据进一步划分到多个桶(文件),每个桶存储部分数据。

📌 分桶原理

  • 哈希分桶:Hive 对指定列计算哈希值,然后取 桶数的余数 来决定数据存放的桶。

  • 桶号计算:桶号 = 哈希值(分桶列) mod 总桶数

实际例子

按姓名分桶(4个桶)

  • 计算姓名的ASCII 码总和,对4 取余,决定数据存放的桶:

    • 张三哈希值 % 4 = 0存入桶 0

    • 李四哈希值 % 4 = 1存入桶 1

    • 王五哈希值 % 4 = 2存入桶 2

    • 赵六哈希值 % 4 = 3存入桶 3

分桶可加速查询,适用于大规模数据、JOIN优化等场景


📌 分桶操作

  • 创建分桶表时,需要指定分桶列桶的数量

📌 分桶的优势

  1. 查询更快:只扫描相关桶,减少数据读取量。

  2. 均衡存储:避免数据倾斜,提升计算效率。

  3. 管理方便:简化数据存储和处理,优化大规模数据管理。


3.2 分桶表的概念

分桶表也叫做桶表,源自建表语法中bucket单词。是一种用于优化查询而设计的表类型。该功能可以让数据分解为若干个部分易于管理。

在分桶时,我们要指定根据哪个字段将数据分为几桶(几个部分)。

数据分桶原理:

Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。


3.3 分桶表的语法

CREATE TABLE table_name (
    col1 data_type,
    col2 data_type, ...
)
CLUSTERED BY (col_name)  -- 指定分桶字段
INTO N BUCKETS;          -- 指定桶的数量

注意:分桶的字段必须是表中已经存在的字段。


3.4 分桶实战1

分桶是由列的哈希值除以桶的个数来决定每条数据划分在哪个桶中。

# 数据准备(id,name,age)

[root@master data]# pwd
/opt/data

[root@master data]# vim stu_info.txt
1,tom,11
2,cat,22
3,dog,33
4,hive,44
5,hbase,55
6,mr,66
7,alice,77
8,scala,88
-- 创建数据库
drop database if exists bucket;
create database if not exists bucket;

-- 创建一个普通的表
create table psn
(
    id   int,
    name string,
    age  int
)
    row format delimited
    fields terminated by ',';
-- 将数据load到这张表中
load data local inpath '/opt/data/stu_info.txt' into table psn;
-- 创建分桶表
create table psn_bucket
(
    id   int,
    name string,
    age  int
)
    clustered by (age)
        into 4 buckets
    row format delimited
        fields terminated by ',';
--  将数据insert到表psn_bucket中
--  (注意:这里和分区表插入数据有所区别,分区表需要select 和指定分区,而分桶则不需要)

insert into psn_bucket select id,name,age from psn;


在HDFS上查看分桶数据

image-20230104222318068

查询数据

我们在linux中使用Hadoop的命令查看一下(与我们猜想的顺序一致)

[root@master data]# hdfs dfs  -cat /user/hive/warehouse/honor_of_kings.db/psn_bucket/*
# 查看结果
8,scala,88
4,hive,44
7,alice,77
3,dog,33
6,mr,66
2,cat,22
5,hbase,55
1,tom,11

[root@master data]# hdfs dfs -cat /user/hive/warehouse/test.db/psn_bucket/000000_0
# 查看结果
8,scala,88
4,hive,44
# 这里设置的桶的个数是4 数据按照 年龄age%4的余数进行放桶(文件) 
11%4 == 3 -----> 000003_0 
22%4 == 2 -----> 000002_0 
33%4 == 1 -----> 000001_0 
44%4 == 0 -----> 000000_0 
55%4 == 3 -----> 000003_0 
66%4 == 2 -----> 000002_0 
77%4 == 1 -----> 000001_0 
88%4 == 0 -----> 000000_0 
# ...以此类推

image-20230419224520296


3.5 分桶实战2

现有美国2021-1-28号,各个县county的新冠疫情累计案例信息,包括确诊病例和死亡病例,数据格式如下所示:

2021-01-28,Juneau City and Borough,Alaska,02110,1108,3
2021-01-28,Kenai Peninsula Borough,Alaska,02122,3866,18
2021-01-28,Ketchikan Gateway Borough,Alaska,02130,272,1
2021-01-28,Kodiak Island Borough,Alaska,02150,1021,5
2021-01-28,Kusilvak Census Area,Alaska,02158,1099,3
2021-01-28,Lake and Peninsula Borough,Alaska,02164,5,0
2021-01-28,Matanuska-Susitna Borough,Alaska,02170,7406,27
2021-01-28,Nome Census Area,Alaska,02180,307,0
2021-01-28,North Slope Borough,Alaska,02185,973,3
2021-01-28,Northwest Arctic Borough,Alaska,02188,567,1
2021-01-28,Petersburg Borough,Alaska,02195,43,0

字段含义如下: count_date(统计日期),county(县),state(州),fips(县编码code),cases(累计确诊病例),deaths(累计死亡病例)。

根据state州把数据分为5桶,建表语句如下:

-- 创建数据库
drop database if exists itcast cascade;
create database if not exists itcast;
use itcast;

-- 创建一个名为t_usa_covid19_bucket的分桶表,用于存储美国covid-19疫情数据
create table if not exists itcast.t_usa_covid19_bucket(
    count_date string,  -- 日期字段,记录数据的日期
    county string,      -- 县级行政单位
    state string,       -- 州级行政单位
    fips int,           -- fips代码,美国用于区分各县的唯一代码
    cases int,          -- 确诊病例数
    deaths int          -- 死亡病例数
)
clustered by(state)    -- 通过state字段进行分桶
into 5 buckets;        -- 数据分成5个桶,用于更有效的查询和存储

在创建分桶表时,还可以指定分桶内的数据排序规则

-- 根据state州分为5桶 每个桶内根据cases确诊病例数倒序排序
create table if not exists itcast.t_usa_covid19_bucket_sort(
      count_date string,  -- 日期字段,记录数据的日期
      county string,      -- 县级行政单位
      state string,       -- 州级行政单位
      fips int,           -- fips代码,美国用于区分各县的唯一代码
      cases int,          -- 确诊病例数
      deaths int          -- 死亡病例数
)
clustered by(state)      -- 通过state字段进行分桶
sorted by (cases desc)   -- 在每个桶内根据cases字段进行倒序排序
into 5 buckets;          -- 数据分成5个桶,用于更有效的查询和存储


3.4 分桶表的数据加载

-- step1:开启分桶的功能 从Hive2.0开始不再需要设置
set hive.enforce.bucketing=true;

-- step2:创建普通hive表itcast.t_usa_covid19中,并加载数据
CREATE TABLE if not exists itcast.t_usa_covid19
    (
       count_date string,
       county string,
       state string,
       fips int,
       cases int,
       deaths int
    )
row format delimited 
fields terminated by ",";

-- 方法一:将源数据上传到HDFS,t_usa_covid19表对应的路径下
hdfs dfs -put /opt/apps/hive/data/us-covid19-counties.dat \
/user/hive/warehouse/itcast.db/t_usa_covid19

-- 方法二:使用LOAD DATA命令将数据从本地文件系统导入到Hive表中
LOAD DATA LOCAL INPATH '/opt/apps/hive/data/us-covid19-counties.dat' INTO TABLE itcast.t_usa_covid19;

-- step3:使用insert+select语法将数据加载到分桶表中
insert into t_usa_covid19_bucket select * from t_usa_covid19;

-- step4:使用insert+select语法将数据加载到排序的分桶表中
insert into t_usa_covid19_bucket_sort select * from t_usa_covid19;

到HDFS上查看t_usa_covid19_bucket底层数据结构可以发现,数据被分为了5个部分。

img

并且从结果可以发现,只要hash_function(bucketing_column)一样的,就一定被分到同一个桶中。


3.5 分桶表与分区表的区别

(1)从表现形式上:

  • 分区表是一个目录,分桶表是文件

(2)从创建语句上:

  • 分区表使用partitioned by 子句指定,以指定字段为伪列,需要指定字段类型

  • 分桶表由clustered by 子句指定,指定字段为真实字段,需要指定桶的个数

(3)从数量上:

  • 分区表的分区个数可以增长,分桶表一旦指定,不能再增长

(4)从作用上:

  • 分区避免全表扫描,根据分区列查询指定目录提高查询速度

  • 分桶保存分桶查询结果的分桶结构(数据已经按照分桶字段进行了hash散列)

  • 分桶表数据进行抽样和JOIN时可以提高MR程序效率

3.5 分桶表的使用好处

和非分桶表相比,分桶表的使用好处有以下几点:

1、 基于分桶字段查询时,减少全表扫描

-- 基于分桶字段state查询来自于New York州的数据
-- 不再需要进行全表扫描过滤
-- 根据分桶的规则hash_function(New York) mod 5计算出分桶编号
-- 查询指定分桶里面的数据就可以找出结果,此时是分桶扫描而不是全表扫描
select *  from t_usa_covid19_bucket
where state="New York";


2、 JOIN时可以提高MR程序效率,减少笛卡尔积数量

例如,假设有两个表A和B,都根据相同的列C进行了分桶操作。如果要对这两个表进行JOIN操作,可以将A表和B表中具有相同C列值的桶进行JOIN操作。这样就可以避免对A表和B表所有数据进行笛卡尔积操作,减少JOIN操作的数据量,提高JOIN操作的效率。


3、 分桶表数据进行抽样

当数据量特别大时,对全体数据进行处理存在困难时,抽样就显得尤其重要了。抽样可以从被抽取的数据中估计和推断出整体的特性,是科学实验、质量检验、社会调查普遍采用的一种经济有效的工作和研究方法。

对于分桶表数据进行抽样时,同一个桶内的数据具有相同的值,采样时可以选择每个桶的一部分数据进行采样,这样可以更好地保留数据的特征,提高采样的代表性。这样做可以减少采样误差,提高采样结果的准确性。

为了深入理解Hive中的表结构优化,本实验旨在通过创建和查询三种不同类型的Hive表(普通表、分区表、分区且分桶表)来展示它们在数据存储和查询性能上的区别。以下是详细的实验任务:



发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Powered By Z-BlogPHP 1.7.3

版权:李翔
备案/许可证编号为:新ICP备2024006115号-1