Hadoop(三):Hive

本文为学习笔记,对应视频教程来自黑马程序员Hive教程

Hive部署

Mysql 安装

卸载Centos7自带mariadb和mysql
1
2
3
4
5
[root@hadoop102 ~]# rpm -qa | grep mariadb
mariadb-libs-5.5.60-1.el7_5.x86_64
[root@hadoop102 ~]# rpm -e mariadb-libs-5.5.60-1.el7_5.x86_64 --nodeps
# 最小化安装不会自带MySQL
[root@hadoop102 ~]# rpm -e --nodeps $(rpm -qa | grep mysql)
mysql安装介质下载

官网下载地址:MySQL Product Archives

Product Version Operating System OS Version
5.7.20 Linux - Generic Linux - Generic(glibc 2.12)(x86,64-bit)
解压安装介质
1
2
3
4
[root@hadoop102 ~]# cd /opt/software/
[root@hadoop102 software]# tar -zxf mysql-5.7.20-linux-glibc2.12-x86_64.tar.gz
# 将解压出的文件夹名称修改为mysql-5.7.20
[root@hadoop102 software]# mv mysql-5.7.20-linux-glibc2.12-x86_64 ../module/mysql-5.7.20
建立用户和组并创建相关目录
1
2
3
4
5
6
[root@hadoop102 mysql-5.7.20]# groupadd mysql
[root@hadoop102 mysql-5.7.20]# useradd -r -g mysql -s /bin/false mysql

[root@hadoop102 mysql-5.7.20]# mkdir -p /data/mysql
[root@hadoop102 mysql-5.7.20]# chown -R mysql:mysql /data
[root@hadoop102 mysql-5.7.20]# chmod 750 /data
配置环境变量
1
2
3
4
5
6
[root@hadoop102 ~]# vim /etc/profile.d/my_env.sh 
#MYSQL_HOME
export MYSQL_HOME=/opt/module/mysql-5.7.20
export PATH=$PATH:$MYSQL_HOME/bin

[root@hadoop102 ~]# source /etc/profile
安装依赖包
1
[root@hadoop102 ~]# yum install libaio
初始化MySQL
  1. 初始化创建mysql数据库

    1
    2
    3
    4
    5
    6
    7
    [root@hadoop102 ~]# mysqld --initialize --user=mysql --basedir=/opt/module/mysql-5.7.20/ --datadir=/data/mysql/
    2022-05-11T10:50:24.777743Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
    2022-05-11T10:50:25.027412Z 0 [Warning] InnoDB: New log files created, LSN=45790
    2022-05-11T10:50:25.068499Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
    2022-05-11T10:50:25.139430Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 29be3489-d118-11ec-ba45-000c2900c11d.
    2022-05-11T10:50:25.140670Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
    2022-05-11T10:50:25.141518Z 1 [Note] A temporary password is generated for root@localhost: L2)cw18vE8lw
  2. 配置mysql.cnf文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 找到配置文件所在位置
    [root@hadoop102 ~]# mysql --help | grep cnf
    order of preference, my.cnf, $MYSQL_TCP_PORT,
    /etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf /opt/module/mysql-5.7.20/my.cnf ~/.my.cnf

    # 编辑配置文件
    [root@hadoop102 ~]# vim /etc/my.cnf
    [mysqld]
    user=mysql
    port=3306
    basedir=/opt/module/mysql-5.7.20
    datadir=/data/mysql
    server_id=1
    socket=/tmp/mysql.sock
    [mysql]
    socket=/tmp/mysql.sock
  3. 配置mysql服务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@hadoop102 ~]# vim /usr/lib/systemd/system/mysqld.service

    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/opt/module/mysql-5.7.20/bin/mysqld --defaults-file=/etc/my.cnf
    LimitNOFILE = 5000
  4. 启动服务并修改密码

    1
    2
    3
    4
    5
    [root@hadoop102 ~]# systemctl start mysqld

    [root@hadoop102 ~]# mysql -uroot -p
    # 修改密码
    mysql> ALTER USER USER() IDENTIFIED BY 'root';
  5. 授权允许远程访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 查看MySQL当前远程访问权限配置
    mysql> use mysql;
    mysql> SELECT User,authentication_string,Host FROM user;
    +---------------+-------------------------------------------+-----------+
    | User | authentication_string | Host |
    +---------------+-------------------------------------------+-----------+
    | root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B | localhost |
    | mysql.session | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | localhost |
    | mysql.sys | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | localhost |
    +---------------+-------------------------------------------+-----------+

    # 修改权限,password 为密码
    GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;

    # 从mysql数据库的grant表中重新加载权限数据
    mysql> FLUSH PRIVILEGES;

Hive 安装 - 远程模式

Hive安装介质的下载与解压

官网下载地址:Apache Hive Downloads

1
2
3
[root@hadoop102 ~]# cd /opt/software/
[root@hadoop102 software]# tar -zxf apache-hive-3.1.3-bin.tar.gz
[root@hadoop102 software]# mv apache-hive-3.1.3-bin ../module/apache-hive-3.1.3
解决hadoop、hive之间guava版本差异
1
2
3
4
5
# 删除 hive 中低版本的 jar 包
[root@hadoop102 ~]# cd /opt/module/apache-hive-3.1.3/
[root@hadoop102 apache-hive-3.1.3]# rm -rf lib/guava-19.0.jar
# 复制 hadoop 中高版本的 jar 包到 hive 的 lib 目录下
[root@hadoop102 apache-hive-3.1.3]# cp /opt/module/hadoop-3.3.2/share/hadoop/common/lib/guava-27.0-jre.jar ./lib/
添加mysql jdbc驱动

官网下载地址:MySQL Community Downloads

1
2
3
4
5
6

[root@hadoop102 eitan]# cd /opt/software/
[root@hadoop102 software]# tar -zxf mysql-connector-java-8.0.29.tar.gz
# 添加mysql jdbc驱动到hive安装包lib/文件下
[root@hadoop102 software]# cd mysql-connector-java-8.0.29
[root@hadoop102 mysql-connector-java-8.0.29]# cp mysql-connector-java-8.0.29.jar /opt/module/apache-hive-3.1.3/lib/
Connector/J version JDBC version MySQL Server version JRE Required JDK Required for Compilation Status
5.1 3.0, 4.0, 4.1, 4.2 5.61, 5.71, 8.01 JRE 5 or higher1 JDK 5.0 AND JDK 8.0 or higher2, 3 General availability
8.0 4.2 5.6, 5.7, 8.0 JRE 8 or higher JDK 8.0 or higher2 General availability. Recommended version.

说明:mysql jdbc 的java驱动只有两个版本,且两个版本都支持mysql-5.7。官方推荐使用8.0版本。

修改hive环境变量文件
1
2
3
4
5
6
[root@hadoop102 ~]# cd /opt/module/apache-hive-3.1.3/conf/
[root@hadoop102 conf]# cp hive-env.sh.template hive-env.sh
[root@hadoop102 conf]# vim hive-env.sh
export HADOOP_HOME=/opt/module/hadoop-3.3.2
export HIVE_CONF_DIR=/opt/module/apache-hive-3.1.3/conf
export HIVE_AUX_JARS_PATH=/opt/module/apache-hive-3.1.3/lib
新增hive-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
[root@hadoop102 conf]# vim hive-site.xml
<configuration>
<!-- 存储元数据mysql相关配置 -->
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://hadoop102:3306/hive?createDatabaseIfNotExist=true&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8</value>
</property>

<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.cj.jdbc.Driver</value>
</property>

<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
</property>

<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>root</value>
</property>

<!-- Bind host on which to run the HiveServer2 Thrift interface -->
<property>
<name>hive.server2.thrift.bind.host</name>
<value>hadoop102</value>
</property>

<!-- 远程模式部署metastore服务地址 -->
<property>
<name>hive.metastore.uris</name>
<value>thrift://hadoop102:9083</value>
</property>

<!-- 关闭元数据存储授权 -->
<property>
<name>hive.metastore.event.db.notification.api.auth</name>
<value>false</value>
</property>

<!-- 关闭元数据存储版本的验证 -->
<property>
<name>hive.metastore.schema.verification</name>
<value>false</value>
</property>
</configuration>
初始化metadata
1
2
[root@hadoop102 ~]# cd /opt/module/apache-hive-3.1.3/
[root@hadoop102 apache-hive-3.1.3]# ./bin/schematool -initSchema -dbType mysql -verbos

校验是否成功:MySQL中创建hive数据库并持有74张表

启动 hive
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 启动 hadoop 集群,hadoop 集群启动脚本在 Hadoop(一):集群搭建.md
[eitan@hadoop102 ~]$ myhadoop.sh start

# 启动 Metastore
[eitan@hadoop102 ~]$ nohup /opt/module/apache-hive-3.1.3/bin/hive --service metastore &

# 启动 Hive
[eitan@hadoop102 ~]$ /opt/module/apache-hive-3.1.3/bin/hive

# 验证是否启动成功
hive> show databases;
OK
default
Time taken: 0.52 seconds, Fetched: 1 row(s)

# 前台启动开启debug日志
/opt/module/apache-hive-3.1.3/bin/hive --service metastore --hiveconf hive.root.logger=DEBUG,console

使用 Hive Beeline Client 连接

Hive服务和客户端关系梳理

HiveServer2通过Metastore服务读写元数据。所以在远程模式下,启动HiveServer2之前必须先首先启动metastore服务。远程模式下,Beeline客户端只能通过HiveServer2服务访问Hive。而Hive Client是通过Metastore服务访问的。具体关系如下:

image-20220512093652882

Hive服务规划部署
hadoop102 hadoop103 hadoop104
Metastore
Mysql
HiveServer2 Beeline Client
修改配置文件
  1. Metastore需要知道HiveServer2运行位置

    1
    2
    3
    4
    5
    6
    7
    [eitan@hadoop102 ~]$ sudo vim /opt/module/apache-hive-3.1.3/conf/hive-site.xml
    # 修改<value>为hadoop103
    <!-- Bind host on which to run the HiveServer2 Thrift interface -->
    <property>
    <name>hive.server2.thrift.bind.host</name>
    <value>hadoop103</value>
    </property>
  2. HiveServer2需要知道Metastore运行位置

    1
    2
    3
    4
    5
    6
    7
    [eitan@hadoop102 ~]$ sudo vim /opt/module/apache-hive-3.1.3/conf/hive-site.xml
    # 确认 metastore 启动在 hadoop102 并监听9083接口
    <!-- 远程模式部署metastore服务地址 -->
    <property>
    <name>hive.metastore.uris</name>
    <value>thrift://hadoop102:9083</value>
    </property>
  3. 开启各项服务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 启动MySQL
    [eitan@hadoop102 ~]$ systemctl start mysqld
    # 启动Hadoop集群
    [eitan@hadoop102 ~]$ myhadoop.sh start
    # 启动metastore服务,只需先启动了MySQL就行与Hadoop无关
    [eitan@hadoop102 ~]$ /opt/module/apache-hive-3.1.3/bin/hive --service metastore
    # 启动hiveserver2,需要提前启动Hadoop
    [eitan@hadoop103 ~]$ /opt/module/apache-hive-3.1.3/bin/hiveserver2
    # 启动beeline,并连接hiveserver2
    [eitan@hadoop104 ~]$ /opt/module/apache-hive-3.1.3/bin/beeline
    beeline> ! connect jdbc:hive2://hadoop103:10000
    Connecting to jdbc:hive2://hadoop103:10000
    Enter username for jdbc:hive2://hadoop103:10000: eitan
    Enter password for jdbc:hive2://hadoop103:10000:
    Connected to: Apache Hive (version 3.1.3)
    Driver: Hive JDBC (version 3.1.3)
    Transaction isolation: TRANSACTION_REPEATABLE_READ
    0: jdbc:hive2://hadoop103:10000>

编写hive启动停止脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[eitan@hadoop102 ~]$ vim bin/myhive.sh 
#!/bin/bash
if [ $# -lt 1 ]
then
echo "No Args Input..."
exit;
fi

case $1 in
"start")
echo "================ 启动 Hive ================"
echo "---------------- 启动 metastore ----------------"
ssh hadoop102 "nohup /opt/module/apache-hive-3.1.3/bin/hive --service metastore > /home/eitan/log/metastore.out 2>&1 &"
echo "---------------- 启动 hiveserver2 ----------------"
ssh hadoop103 "nohup /opt/module/apache-hive-3.1.3/bin/hiveserver2 > /home/eitan/log/hiveserver2.out 2>&1 &"
;;
"stop")
echo "================ 关闭 Hive ================"
echo "---------------- 关闭 metastore ----------------"
ssh hadoop102 "ps -ef | grep metastore | grep -v grep | awk '{print $2}' | xargs kill -9"
echo "---------------- 关闭 hiveserver2 ----------------"
ssh hadoop103 "ps -ef | grep hiveserver2 | grep -v grep | awk '{print $2}' | xargs kill -9"
;;
*)
echo "Input Args Error..."
;;
esac

[eitan@hadoop102 ~]$ chmod +x bin/myhive.sh
[eitan@hadoop102 ~]$ xsync bin/myhive.sh

Hive 的数据定义语言(DDL)

完整建表语法树

image-20220512170423242

  • 蓝色字体是建表语法的关键字,用于指定某些功能。

  • **[]**中括号的语法表示可选。

  • **|**表示使用的时候,左右语法二选一。

  • 建表语句中的语法顺序要和上述语法规则保持一致。

Hive数据类型

Hive中的数据类型指的是Hive表中的列字段类型。Hive数据类型整体分为两个类别:原生数据类型(primitive data type)和复杂数据类型(complex data type)。

原生数据类型包括:数值类型、时间类型、字符串类型、杂项数据类型;

复杂数据类型包括:array数组、map映射、struct结构、union联合体。

官方文档链接:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types

Hive读写文件机制

Hive读写文件流程

Hive读取文件机制:首先调用InputFormat(默认TextInputFormat),返回一条一条kv键值对记录(默认是一行对应一条记录)。然后调用SerDe(默认LazySimpleSerDe)的Deserializer,将一条记录中的value根据分隔符切分为各个字段。

Hive写文件机制:将Row写入文件时,首先调用SerDe(默认LazySimpleSerDe)的Serializer将对象转换成字节序列,然后调用OutputFormat将数据写入HDFS文件中。

image-20220512173122549

SerDe概念及相关语法

SerDe是Serializer、Deserializer的简称,目的是用于序列化和反序列化。序列化是对象转化为字节码的过程;而反序列化是字节码转换为对象的过程。

在Hive的建表语句中,和SerDe相关的语法为:

image-20220512194839798

其中ROW FORMAT是语法关键字,DELIMITED和SERDE二选其一。

如果使用DELIMITED表示使用默认的LazySimpleSerDe类来处理数据。如果数据文件格式比较特殊可以使用ROW FORMAT SERDE serde_name指定其他的Serde类来处理数据,甚至支持用户自定义SerDe类。

LazySimpleSerDe是Hive默认的序列化类,包含4种子语法,分别用于指定字段之间集合元素之间map映射 kv之间换行的分隔符号:

image-20220512195056138

默认分隔符为 ‘\001’

二进制 十进制 十六进制 缩写
0000 0001 1 01 SOH

Hive数据存储路径

默认存储路径

Hive表默认存储路径是由${HIVE_HOME}/conf/hive-site.xml配置文件的hive.metastore.warehouse.dir属性指定。默认值是:/user/hive/warehouse。

指定存储路径

在Hive建表的时候,可以通过LOCATION语法来更改数据在HDFS上的存储路径,使得建表加载数据更加灵活方便。

语法:LOCATION ‘

练习

原生数据类型建表练习

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

1
2
3
4
5
6
7
8
9
10
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(次要定位)

实践:

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE 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 "次要定位"
) comment "王者荣耀射手信息"
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";
1
2
# 上传文件
[eitan@hadoop102 ~]$ hadoop fs -put documents/txt/archer.txt /user/hive/warehouse/itcast.db/t_archer/
复杂数据类型建表练习

需求:文件hot_hero_skin_price.txt中记录了手游《王者荣耀》热门英雄的相关皮肤价格信息,内容如下,要求在Hive中建表映射成功该文件。

1
2
3
4
5
1,孙悟空,53,西部大镖客:288-大圣娶亲:888-全息碎片:0-至尊宝:888-地狱火:1688
2,鲁班七号,54,木偶奇遇记:288-福禄兄弟:288-黑桃队长:60-电玩小子:2288-星空梦想:0
3,后裔,53,精灵王:288-阿尔法小队:588-辉光之辰:888-黄金射手座:1688-如梦令:1314
4,铠,52,龙域领主:288-曙光守护者:1776
5,韩信,52,飞衡:1788-逐梦之影:888-白龙吟:1188-教廷特使:0-街头霸王:888

字段:id、name(英雄名称)、win_rate(胜率)、skin_price(皮肤及价格)

实践:

1
2
# 先上传文件
[eitan@hadoop102 ~]$ hadoop fs -put -p documents/txt/hot_hero_skin_price.txt /user/hive/warehouse/itcast.db/t_hot_hero_skin_price/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 后建表并指定文件所在位置
CREATE TABLE t_hot_hero_skin_price (
id int comment "ID",
name string comment "英雄名称",
win_rate int comment "胜率",
skin_price map<string,int> comment "皮肤及价格"
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY "," -- 字段之间分隔符
COLLECTION ITEMS TERMINATED BY "-" -- 集合元素之间分隔符
MAP KEYS TERMINATED BY ":"
LOCATION "/user/hive/warehouse/itcast.db/t_hot_hero_skin_price";

SELECT * FROM t_hot_hero_skin_price;

Hive内、外部表

内部表 外部表
创建方式 默认情况 使用EXTERNAL语法关键字
Hive管理范围 元数据、表数据 元数据
删除表结果 删除元数据及HDFS上的文件数据 只删除元数据
操作 支持ARCHIVE,UNARCHIVE,TRUNCATE,MERGE,CONCATENATE 不支持
事务 支持ACID/事务性 不支持
缓存 支持结果缓存 不支持

Hive分区表

概念: 分区的概念提供了一种将Hive表数据分离为多个文件/目录的方法。不同分区对应着不同的文件夹,同一分区的数据存储在同一个文件夹下。只需要根据分区值找到对应的文件夹,扫描本分区下的文件即可,避免全表数据扫描。

静态分区

描述:静态分区指的是分区的字段值是由用户在加载数据的时候手动指定的。

语法:

1
LOAD DATA [LOCAL] INPATH "" INTO TABLE table_name PARTITION (分区字段 = '分区值');

[LOCAL] 表示数据是位于本地文件系统还是HDFS文件系统

分区字段不能是表中已经存在的

案例:

有一组文件位于本地文件系统上,请为其建立分区表。

1
2
3
4
5
6
7
8
9
10
11
12
[eitan@hadoop102 ~]$ cd documents/txt/hero/
[eitan@hadoop102 hero]$ ll
总用量 24
-rw-rw-r--. 1 eitan eitan 480 5月 13 09:48 archer.txt
-rw-rw-r--. 1 eitan eitan 292 5月 13 09:48 assassin.txt
-rw-rw-r--. 1 eitan eitan 883 5月 13 09:48 mage.txt
-rw-rw-r--. 1 eitan eitan 289 5月 13 09:48 support.txt
-rw-rw-r--. 1 eitan eitan 446 5月 13 09:48 tank.txt
-rw-rw-r--. 1 eitan eitan 837 5月 13 09:48 warrior.txt

# 需要把文件同步到hiveserver2所在机器hadoop103上
[eitan@hadoop102 ~]$ xsync documents/txt/hero/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-- 建表时需要指定分区字段
CREATE TABLE t_static_hero_partition (
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 "次要定位"
) COMMENT "王者荣耀英雄信息"
PARTITIONED BY (role STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";

-- 加载本地文件并为其分区
LOAD DATA LOCAL INPATH "/home/eitan/documents/txt/hero/archer.txt" INTO TABLE t_static_hero_partition PARTITION (role = "sheshou");
LOAD DATA LOCAL INPATH "/home/eitan/documents/txt/hero/assassin.txt" INTO TABLE t_static_hero_partition PARTITION (role = "cike");
LOAD DATA LOCAL INPATH "/home/eitan/documents/txt/hero/mage.txt" INTO TABLE t_static_hero_partition PARTITION (role = "fashi");
LOAD DATA LOCAL INPATH "/home/eitan/documents/txt/hero/support.txt" INTO TABLE t_static_hero_partition PARTITION (role = "fuzhu");
LOAD DATA LOCAL INPATH "/home/eitan/documents/txt/hero/tank.txt" INTO TABLE t_static_hero_partition PARTITION (role = "tanke");
LOAD DATA LOCAL INPATH "/home/eitan/documents/txt/hero/warrior.txt" INTO TABLE t_static_hero_partition PARTITION (role = "zhanshi");

-- 查询使用分页
SELECT * FROM t_static_hero_partition WHERE role = "sheshou";
动态分区

描述:动态分区指的是分区的字段值是基于查询结果自动推断出来的。核心语法就是insert+select。

启用hive动态分区,需要在hive会话中设置两个参数:

set hive.exec.dynamic.partition=true;

set hive.exec.dynamic.partition.mode=nonstrict;

语法:

1
INSERT INTO TABLE table_name PARTITION (分区字段) SELECT table_fields FROM table_name; 

SELECT 查询字段必须要与 INSERT 后的 table_name 表字段一一对应,并最后加上 PARTITION 的分区字段

案例: 对学生表按地区、年龄分区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 创建原数据表,并把响应数据放入目标目录下
CREATE TABLE t_student
(
id int COMMENT "ID",
name string COMMENT "学生姓名",
sex string COMMENT "姓名",
age int COMMENT "年龄",
area string COMMENT "地区"
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ",";

-- 创建动态分区数据表
CREATE TABLE t_dynamic_student_partition
(
id int COMMENT "ID",
name string COMMENT "学生姓名",
sex string COMMENT "姓名"
) PARTITIONED BY (area string COMMENT "地区",age int COMMENT "年龄")
ROW FORMAT DELIMITED FIELDS TERMINATED BY ",";

-- 通过 INSERT...SELECT 语句插入数据,Hive会启动MAPREDUCE逐行扫描按所定义分区将数据划分到不懂的子目录中
INSERT INTO TABLE t_dynamic_student_partition SELECT id, name, sex, area, age FROM t_student;

如果表中定义了PARTITIONED,则INSERT语句中PARTITION不用写,并且写了分区顺序也是按表定义的来。

Hive分桶表

概念: 将所给数据按规则划分到不同物理文件中。

语法:

1
2
3
4
5
--分桶表建表语句
CREATE [EXTERNAL] TABLE [db_name.]table_name
[(col_name data_type, ...)]
CLUSTERED BY (col_name)
INTO N BUCKETS;

案例:

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

1
2
3
4
5
6
7
8
9
10
11
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(累计死亡病例)。

实践:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
--step1:开启分桶的功能 从Hive2.0开始不再需要设置
set hive.enforce.bucketing=true;

--step2:创建分桶表
CREATE TABLE t_usa_covid19_bucket_sort
(
count_date string COMMENT "统计日期",
county string COMMENT "县",
state string COMMENT "州",
fips int COMMENT "县编码 code",
cases int COMMENT "累计确诊病例",
deaths int COMMENT "累计死亡病例"
)
-- 按 state 分组后按 case 降序排序
CLUSTERED BY (state) SORTED BY (cases DESC) INTO 5 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

--step3:创建普通表,并上传数据
CREATE TABLE t_usa_covid19
(
count_date string COMMENT "统计日期",
county string COMMENT "县",
state string COMMENT "州",
fips int COMMENT "县编码 code",
cases int COMMENT "累计确诊病例",
deaths int COMMENT "累计死亡病例"
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

[eitan@hadoop102 ~]$ hadoop fs -put documents/txt/us-covid19-counties.dat /user/hive/warehouse/itcast.db/t_usa_covid19

--step4:使用insert+select语法将数据加载到分桶表中
INSERT INTO t_usa_covid19_bucket_sort SELECT * FROM t_usa_covid19;

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

Hive事务表

Hive事务表的局限性
  • 尚不支持BEGIN,COMMIT和ROLLBACK。所有语言操作都是自动提交的;
  • 仅支持ORC文件格式(STORED AS ORC)
  • 默认情况下事务配置为关闭。需要配置参数开启使用;
  • 表必须是分桶表(Bucketed)才可以使用事务功能;
  • 表参数transactional必须为true
  • 外部表不能成为ACID表,不允许从非ACID会话读取/写入ACID表。
Hive事务表实践
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
--Hive中事务表的创建使用
-- 开启事务配置(可以使用set设置当前session生效 也可以配置在hive-site.xml中)
-- 从Hive2.0开始不再需要 是否开启分桶功能
set hive.enforce.bucketing = true;
-- Hive是否支持并发
set hive.support.concurrency = true;
-- 动态分区模式 非严格
set hive.exec.dynamic.partition.mode = nonstrict
set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
--是否在Metastore实例上运行启动线程和清理线程
set hive.compactor.initiator.on = true;
--在此metastore实例上运行多少个压缩程序工作线程。
set hive.compactor.worker.threads = 1;

-- 创建Hive事务表
CREATE TABLE trans_student
(
id int,
name String,
age int
) CLUSTERED BY (id) INTO 2 BUCKETS -- 按id分桶
STORED AS ORC -- 以ORC文件格式存储
TBLPROPERTIES ('transactional' = 'true');

INSERT INTO trans_student VALUES (1, "allen", 18);

SELECT * FROM trans_student;

Hive视图

概念

Hive中的视图(view)是一种虚拟表,只保存定义,不实际存储数据。通常从真实的物理表查询中创建生成视图,也可以从已经存在的视图上创建新视图。

创建视图时,将冻结视图的架构,如果删除或更改基础表,则视图将失败,并且视图不能存储数据,操作数据,只能查询。

概况起来就是:视图是用来简化操作的,它其实是一张虚表,在视图中不缓冲记录,也没有提高查询性能。

视图语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 1、创建视图
CREATE VIEW v_usa_covid19 AS SELECT count_date, county,state,deaths FROM t_usa_covid19 LIMIT 5;
CREATE VIEW v_usa_covid19_from_view AS SELECT * FROM v_usa_covid19 LIMIT 2;
-- 2、显示当前已有的视图
SHOW VIEWS;
-- 3、视图的查询使用
SELECT * FROM v_usa_covid19;
-- 4、查看视图定义
SHOW CREATE TABLE v_usa_covid19;
-- 5、删除视图
DROP VIEW v_usa_covid19_from_view;
-- 6、更改视图属性
ALTER VIEW v_usa_covid19 SET TBLPROPERTIES ("comment" = "this is a view");
-- 7、更改视图定义
ALTER VIEW v_usa_covid19 AS SELECT county,deaths FROM t_usa_covid19 LIMIT 2;

Hive物化视图

物化视图、视图区别
  1. 视图是虚拟的,逻辑存在的,只有定义没有存储数据;
  2. 物化视图是真实的,物理存在的,里面存储着预计算的数据;
  3. 视图的目的是简化降低查询的复杂度,而物化视图的目的是提高查询性能。
物化视图语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
--物化视图的创建语法
CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db_name.]materialized_view_name
[DISABLE REWRITE]
[COMMENT materialized_view_comment]
[PARTITIONED ON (col_name, ...)]
[CLUSTERED ON (col_name, ...) | DISTRIBUTED ON (col_name, ...) SORTED ON (col_name, ...)]
[
[ROW FORMAT row_format]
[STORED AS file_format]
| STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)]
]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
AS SELECT ...;

-- Drops a materialized view
DROP MATERIALIZED VIEW [db_name.]materialized_view_name;
-- Shows materialized views (with optional filters)
SHOW MATERIALIZED VIEWS [IN database_name];
-- Shows information about a specific materialized view
DESCRIBE [EXTENDED | FORMATTED] [db_name.]materialized_view_name;
-- 数据源变更了需要手动执行更新物化视图
ALTER MATERIALIZED VIEW [db_name.]materialized_view_name REBUILD;
  1. 物化视图创建后,select查询执行数据自动落地,”自动”也即在query的执行期间,任何用户对该物化视图是不可见的;

  2. 默认该物化视图可被用于查询优化器optimizer查询重写(在物化视图创建期间可以通过DISABLE REWRITE参数设置禁止使用);

  3. SerDe和storage format非强制参数,可以用户配置,默认可用hive.materializedview.serde、 hive.materializedview.fileformat;

  4. 物化视图可以使用custom storage handlers存储在外部系统(如druid)

1
2
3
CREATE MATERIALIZED VIEW druid_wiki_mv
STORED AS 'org.apache.hadoop.hive.druid.DruidStorageHandler'
AS SELECT __time, page, user, c_added, c_removed FROM src;
  1. 物化视图创建后即可用于相关查询的加速,用户提交查询query,若该query经过重写后可命中已建视图,则被重写命中相关已建视图实现查询加速。是否重写查询使用物化视图可以通过全局参数控制(默认为true):
1
SET hive.materializedview.rewriting=true;

用户可选择性的失能物化视图的重写:

1
ALTER MATERIALIZED VIEW [db_name.]materialized_view_name ENABLE|DISABLE REWRITE;
案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-- 1、Hive是否支持并发
set hive.support.concurrency = true;
-- 2、设置事务管理器
set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
-- 3、创建事务表
CREATE TABLE trans_student
(
id int,
name string,
area string
) CLUSTERED BY (id) INTO 2 BUCKETS
STORED AS ORC
TBLPROPERTIES ("transactional" = "true");
-- 4、往事务表插入数据
INSERT INTO trans_student SELECT id, name, area FROM t_student;
-- 5、不用物化视图查询聚合结果
SELECT area, count(*) FROM trans_student GROUP BY area;
-- 6、创建物化视图
CREATE MATERIALIZED VIEW m_student_agg AS SELECT age, count(*) FROM trans_student GROUP BY age;
-- 7、再次查询
SELECT area, count(*) FROM trans_student GROUP BY area;
-- 8、失能物化视图
ALTER MATERIALIZED VIEW m_student_agg DISABLE REWRITE;
-- 9、查询执行计划,发现查询的表重物化视图又改回了原事务表
EXPLAIN SELECT area, count(*) FROM trans_student GROUP BY area;

Database(数据库)DDL操作

Create Database
1
2
3
4
CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name
[COMMENT database_comment]
[LOCATION hdfs_path]
[WITH DBPROPERTIES (property_name=property_value, ...)];

COMMENT:数据库的注释说明语句

LOCATION:指定数据库在HDFS存储位置,默认/user/hive/warehouse

WITH DBPROPERTIES:用于指定一些数据库的属性配置。

Describe Database
1
DESCRIBE DATABASE/SCHEMA [EXTENDED] db_name;

EXTENDED:用于显示更多信息。

Use Database
1
USE database_name;
Drop Database
1
DROP (DATABASE|SCHEMA) [IF EXISTS] database_name [RESTRICT|CASCADE];

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

Alter Database
1
2
3
4
5
6
7
8
--更改数据库属性
ALTER (DATABASE|SCHEMA) database_name SET DBPROPERTIES (property_name=property_value, ...);

--更改数据库所有者
ALTER (DATABASE|SCHEMA) database_name SET OWNER [USER|ROLE] user_or_role;

--更改数据库位置
ALTER (DATABASE|SCHEMA) database_name SET LOCATION hdfs_path;

Table(表)DDL操作

Describe Table
1
DESCRIBE [FORMATTED|EXTENDED] [db_name.]table_name;
Drop Table
1
DROP TABLE [IF EXISTS] table_name [PURGE]; 

如果已配置垃圾桶(且未指定PURGE),则该表对应的数据实际上将移动到.Trash/Current目录,而元数据完全丢失。如果指定了PURGE,则表数据不会进入.Trash/Current目录,跳过垃圾桶直接被删除。

Truncate Table
1
TRUNCATE [TABLE] table_name;

从表中删除所有行。可以简单理解为清空表的所有数据但是保留表的元数据结构。如果HDFS启用了垃圾桶,数据将被丢进垃圾桶,否则将被删除。

Alter Table
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
-- 1、更改表名
ALTER TABLE table_name RENAME TO new_table_name;
-- 2、更改表属性
ALTER TABLE table_name SET TBLPROPERTIES (property_name = property_value, ... );
-- 3、更改表注释
ALTER TABLE student SET TBLPROPERTIES ('comment' = "new comment for student table");
-- 4、更改SerDe属性
ALTER TABLE table_name SET SERDE serde_class_name [WITH SERDEPROPERTIES (property_name = property_value, ... )];
ALTER TABLE table_name [PARTITION partition_spec] SET SERDEPROPERTIES serde_properties;
ALTER TABLE table_name SET SERDEPROPERTIES ('field.delim' = ',');
-- 5、移除SerDe属性
ALTER TABLE table_name [PARTITION partition_spec] UNSET SERDEPROPERTIES (property_name, ... );

-- 6、更改表的文件存储格式 该操作仅更改表元数据。现有数据的任何转换都必须在Hive之外进行。
ALTER TABLE table_name SET FILEFORMAT file_format;
-- 7、更改表的存储位置路径
ALTER TABLE table_name SET LOCATION "new location";

-- 8、更改列名称/类型/位置/注释
CREATE TABLE test_change (a int, b int, c int);
-- First change column a's name to a1.
ALTER TABLE test_change CHANGE a a1 INT;
-- Next change column a1's name to a2, its data type to string, and put it after column b.
ALTER TABLE test_change CHANGE a1 a2 STRING AFTER b;
-- The new table's structure is: b int, a2 string, c int.
-- Then change column c's name to c1, and put it as the first column.
ALTER TABLE test_change CHANGE c c1 INT FIRST;
-- The new table's structure is: c1 int, b int, a2 string.
-- Add a comment to column a1
ALTER TABLE test_change CHANGE a1 a1 INT COMMENT 'this is column a1';

-- 9、添加/替换列
-- 使用ADD COLUMNS,您可以将新列添加到现有列的末尾但在分区列之前。
-- REPLACE COLUMNS 将删除所有现有列,并添加新的列集。
ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type,...);

Partition(分区)DDL操作

Add Partition
1
2
3
4
5
6
-- 一次添加一个分区
ALTER TABLE table_name ADD PARTITION (dt='20170101') location '/user/hadoop/warehouse/table_name/dt=20170101';

-- 一次添加多个分区
ALTER TABLE table_name ADD PARTITION (dt='2008-08-08', country='us') location '/path/to/us/part080808'
PARTITION (dt='2008-08-09', country='us') location '/path/to/us/part080809';

分区值仅在为字符串时才应加引号。位置必须是数据文件所在的目录。

ADD PARTITION会更改表元数据,但不会加载数据。如果分区位置中不存在数据,查询将不会返回任何结果。

Rename Partition
1
2
3
-- 重命名分区
ALTER TABLE table_name PARTITION partition_spec RENAME TO PARTITION partition_spec;
ALTER TABLE table_name PARTITION (dt='2008-08-09') RENAME TO PARTITION (dt='20080809');
Delete Partition
1
2
3
ALTER TABLE table_name DROP [IF EXISTS] PARTITION (dt='2008-08-08', country='us');
-- 直接删除数据 不进垃圾桶
ALTER TABLE table_name DROP [IF EXISTS] PARTITION (dt='2008-08-08', country='us') PURGE;

将删除该分区的数据和元数据。

Msck Partition
1
2
-- 修复分区
MSCK [REPAIR] TABLE table_name [ADD/DROP/SYNC PARTITIONS];

MSCK命令的默认选项是“添加分区”。使用此选项,它将把HDFS上存在但元存储中不存在的所有分区添加到元存储中。DROP PARTITIONS选项将从已经从HDFS中删除的metastore中删除分区信息。SYNC PARTITIONS选项等效于调用ADD和DROP PARTITIONS。

如果存在大量未跟踪的分区,则可以批量运行MSCK REPAIR TABLE,以避免OOME(内存不足错误)。

Alter Partition
1
2
3
4
-- 更改分区文件存储格式
ALTER TABLE table_name PARTITION (dt='2008-08-09') SET FILEFORMAT file_format;
-- 更改分区位置
ALTER TABLE table_name PARTITION (dt='2008-08-09') SET LOCATION "new location";

Hive Show显示语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
-- 1、显示所有数据库 SCHEMAS和DATABASES的用法 功能一样
SHOW DATABASES|SCHEMAS;

-- 2、显示当前数据库所有表/视图/物化视图/分区/索引
SHOW TABLES [IN database_name]; --指定某个数据库

-- 3、显示当前数据库下所有视图
SHOW VIEWS;
-- show all views that start with "test_"
SHOW VIEWS 'test_*';
-- show views from database database_name
SHOW VIEWS [IN/FROM database_name];

-- 4、显示当前数据库下所有物化视图
SHOW MATERIALIZED VIEWS [IN/FROM database_name];

-- 5、显示表分区信息,分区按字母顺序列出,不是分区表执行该语句会报错
SHOW PARTITIONS table_name;

-- 6、显示表/分区的扩展信息
SHOW TABLE EXTENDED [IN|FROM database_name] LIKE table_name;

-- 7、显示表的属性信息
SHOW TBLPROPERTIES table_name;

-- 8、显示表、视图的创建语句
SHOW CREATE TABLE ([db_name.]table_name|view_name);

-- 9、显示表中的所有列,包括分区列。
SHOW COLUMNS (FROM|IN) table_name [(FROM|IN) db_name];

--10、显示当前支持的所有自定义和内置的函数
SHOW FUNCTIONS;

-- 11、Describe desc
-- 查看表信息
DESC EXTENDED table_name;
-- 查看表信息(格式化美观)
DESC FORMATTED table_name;
-- 查看数据库相关信息
DESC DATABASE database_name;

Hive 的数据操纵语言(DML)

DML-LOAD加载数据

LOAD语法
1
2
3
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] [INPUTFORMAT 'inputformat' SERDE 'serde'] (3.0 or later)
  1. filepath

    filepath表示的待移动数据的路径,可以引用一个文件(在这种情况下,Hive将文件移动到表中),也可以是一个目录(在这种情况下,Hive将把该目录中的所有文件移动到表中)。

    具有schema的完整URI,例如:hdfs://namenode:9000/user/hive/project/data1

  2. LOCAL

    如果指定了LOCAL, load命令将在本地文件系统中查找文件路径。

    如果没有指定LOCAL关键字,如果filepath指向的是一个完整的URI,hive会直接使用这个URI。否则Hive会使用hadoop配置文件中定义的schema 和 authority,即参数fs.default.name指定的(默认HDFS)。

  3. OVERWRITE

    如果使用了OVERWRITE关键字,则目标表(或者分区)中的内容会被删除,然后再将 filepath 指向的文件/目录中的内容添加到表/分区中。

案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
-- step1:建表
-- 建表 student_local 用于演示从本地加载数据
CREATE TABLE student_local
(
num int,
name string,
sex string,
age int,
dept string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
-- 建表 student_hdfs 用于演示从HDFS加载数据
CREATE TABLE student_hdfs
(
num int,
name string,
sex string,
age int,
dept string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
-- 建表 student_hdfs_p 用于演示从HDFS加载数据到分区表
CREATE TABLE student_hdfs_p
(
num int,
name string,
sex string,
age int,
dept string
) PARTITIONED BY (country string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';


-- step2:加载数据
-- 从本地加载数据 数据位于HS2本地文件系统 本质是hadoop fs -put上传操作
LOAD DATA LOCAL INPATH "/home/eitan/documents/txt/students.txt" INTO TABLE student_local;
-- 从HDFS加载数据 数据位于HDFS文件系统根目录下 本质是hadoop fs -mv 移动操作
LOAD DATA INPATH "/students.txt" INTO TABLE student_hdfs;
-- 从HDFS加载数据到分区表中并制定分区 数据位于HDFS文件系统根目录下
LOAD DATA INPATH "/students.txt" INTO TABLE student_hdfs_p PARTITION (country = "China");
Hive3.0 Load新特性

Hive 3.0及更高版本中,除了移动复制操作之外,还支持其他加载操作,因为Hive在内部在某些场合下会将加载重写为INSERT AS SELECT。

比如,如果表具有分区,则load命令没有指定分区,则将load转换为INSERT AS SELECT,并假定最后一组列为分区列。如果文件不符合预期的架构,它将引发错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
------- hive 3.0 load命令新特性 ------------------
-- tab1.txt内容如下
11,22,1
33,44,2

-- 创建表
CREATE TABLE IF NOT EXISTS tab1
(
col1 int,
col2 int
) PARTITIONED BY (col3 int)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

-- 加载数据
LOAD DATA LOCAL INPATH "/home/eitan/documents/txt/tab1.txt" INTO TABLE tab1;

本来加载的时候没有指定分区,语句是报错的,但是文件的格式符合表的结构,前两个是col1,col2,最后一个是分区字段col3,则此时会将load语句转换成为insert as select语句。

DML-Insert插入数据

insert + select
1
2
3
4
-- Hive中insert主要是结合select查询语句使用,将查询结果插入到表中,例如:
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;

INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;

INSERT OVERWRITE将覆盖表或分区中的任何现有数据。

如果查询出来的数据类型和插入表格对应的列数据类型不一致,将会进行转换,但是不能保证转换一定成功,转换失败的数据将会为NULL。

multiple inserts多重插入

multiple inserts可以翻译成为多次插入,多重插入,核心是:一次扫描,多次插入。其功能也体现出来了就是减少扫描的次数。

1
2
3
4
5
6
7
8
9
10
------------ multiple inserts ----------------------
-- 当前库下已有一张表student
select * from student;
-- 创建两张新表
create table student_insert1(sno int);
create table student_insert2(sname string);
-- 多重插入
FROM t_student
INSERT OVERWRITE TABLE student_insert1 SELECT id
INSERT OVERWRITE TABLE student_insert2 SELECT name;
dynamic partition insert动态分区插入

分区的值是由后续的select查询语句的结果来动态确定的。根据查询结果自动分区。案例参照 分区表-动态分区

insert + directory导出数据
1
2
3
4
5
6
7
8
9
-- 标准语法:
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
[ROW FORMAT row_format] [STORED AS file_format]
SELECT ... FROM ...

-- 多重导出 Hive extension (multiple inserts):
FROM from_statement
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...

导出操作是一个OVERWRITE覆盖操作。

1
2
3
4
5
6
7
8
9
--1、导出查询结果到HDFS指定目录下
INSERT OVERWRITE DIRECTORY '/tmp/hive_export/e1' SELECT * FROM t_student;

--2、导出时指定分隔符和文件存储格式
INSERT OVERWRITE DIRECTORY '/tmp/hive_export/e2' ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
SELECT * FROM t_student;

--3、导出数据到本地文件系统指定目录下
INSERT OVERWRITE LOCAL DIRECTORY '/home/eitan/hive_export/e1' STORED AS ORC SELECT * FROM t_student;

Hive Transaction事务

实现原理
  1. 用HDFS文件作为原始数据(基础数据),用delta保存事务操作的记录增量数据;

  2. 正在执行中的事务,是以一个staging开头的文件夹维护的,执行结束就是delta文件夹。每次执行一次事务操作都会有这样的一个delta增量文件夹;

  3. 当访问Hive数据时,根据HDFS原始文件和delta增量文件做合并,查询最新的数据。

合并器(Compactor)
  1. 随着表的修改操作,创建了越来越多的delta增量文件,就需要合并以保持足够的性能。

  2. 合并器Compactor是一套在Hive Metastore内运行,支持ACID系统的后台进程。所有合并都是在后台完成的,不会阻止数据的并发读、写。合并后,系统将等待所有旧文件的读操作完成后,删除旧文件。

  3. 合并操作分为两种,minor compaction(小合并)、major compaction(大合并):

    1. 小合并会将一组delta增量文件重写为单个增量文件,默认触发条件为10个delta文件;

    2. 大合并将一个或多个增量文件和基础文件重写为新的基础文件,默认触发条件为delta文件相应于基础文件占比,10%。

      参数 说明
      hive.compactor.delta.num.threshold Specifies the number of delta directories in a partition that triggers an automatic minor compaction.The default value is 10.
      hive.compactor.delta.pct.threshold Specifies the percentage size of delta files relative to the corresponding base files that triggers an automatic major compaction. The default value is. 1, which is 10 percent.

DML-Update、Delete更新、删除数据

Hive事务表-Hive事务表实践

Hive 的数据查询语言(DQL)

语法树
1
2
3
4
5
6
7
8
9
10
[WITH CommonTableExpression (, CommonTableExpression)*] 
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT [offset,] rows]
  • ALL和DISTINCT选项指定是否应返回重复的行。如果没有给出这些选项,则默认值为ALL(返回所有匹配的行)。DISTINCT指定从结果集中删除重复的行。
执行顺序

在查询过程中执行顺序:from > where > group(含聚合)> having >order > select;

  1. 聚合语句(sum,min,max,avg,count)要比having子句优先执行

  2. where子句在查询过程中执行优先级别优先于聚合语句(sum,min,max,avg,count)

1
2
3
4
5
select state,sum(deaths) as cnts
from t_usa_covid19_p
where count_date = "2021-01-28"
group by state
having cnts> 10000;
ORDER BY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---order by
--根据字段进行排序
select * from t_usa_covid19_p
where count_date = "2021-01-28"
and state ="California"
order by deaths; --默认asc null first

select * from t_usa_covid19_p
where count_date = "2021-01-28"
and state ="California"
order by deaths desc; --指定desc null last

--强烈建议将LIMIT与ORDER BY一起使用。避免数据集行数过大
--当hive.mapred.mode设置为strict严格模式时,使用不带LIMIT的ORDER BY时会引发异常。
select * from t_usa_covid19_p
where count_date = "2021-01-28"
and state ="California"
order by deaths desc
limit 3;
CLUSTER BY
1
2
3
4
5
6
7
8
9
--cluster by
select * from student;
--不指定reduce task个数
--日志显示:Number of reduce tasks not specified. Estimated from input data size: 1
select * from student cluster by sno;

--手动设置reduce task个数
set mapreduce.job.reduces =2;
select * from student cluster by sno;

Hive SQL中的CLUSTER BY语法可以指定根据后面的字段将数据分组,每组内再根据这个字段正序排序(不允许指定排序规则),概况起来就是:根据同一个字段,分且排序

DISTRIBUTE BY +SORT BY
1
2
-- 案例:把学生表数据根据性别分为两个部分,每个分组内根据年龄的倒序排序。
select * from student distribute by sex sort by sage desc;

如果说CLUSTER BY的功能是分且排序(同一个字段),那么DISTRIBUTE BY +SORT BY就相当于把cluster by的功能一分为二:DISTRIBUTE BY负责分,SORT BY负责分组内排序,并且可以是不同的字段。

sort by不是全局排序,其在数据进入reducer前完成排序。因此,如果用sort by进行排序,并且设置mapred.reduce.tasks>1,则sort by只保证每个reducer的输出有序,不保证全局有序。

distribute by(字段)根据指定字段将数据分到不同的reducer,分发算法是hash散列。

Union联合查询
1
select_statement UNION [ALL | DISTINCT] select_statement UNION [ALL | DISTINCT] select_statement ...
Common Table Expressions(CTE)
1
2
3
4
--选择语句中的CTE
with q1 as (select sno,sname,sage from student where sno = 95002)
select *
from q1;

公用表表达式(CTE)是一个临时结果集,该结果集是从WITH子句中指定的简单查询派生而来的,该查询紧接在SELECT或INSERT关键字之前。

join连接查询
  1. inner join

    连接的两个表中都存在与连接条件相匹配的数据才会被留下来。

  2. left join

    join时以左表的全部数据为准,右边与之关联;左表数据全部返回,右表关联上的显示返回,关联不上的显示null返回。

  3. right jion

    join时以右表的全部数据为准,左边与之关联;右表数据全部返回,左表关联上的显示返回,关联不上的显示null返回。

  4. full outer join

    它等价于对这两个数据集合分别进行左外连接和右外连接,然后再使用消去重复行的操作将上述两个结果集合并为一个结果集。

    image-20220513231011099

  5. left semi join

    只返回左边表的记录的字段,前提是其记录对于右边的表满足ON语句中的判定条件。相当于inner join但是只返回左边的字段。

  6. cross join

    相当于无条件的inner join。

  7. join注意事项

    • 如果每个表在联接子句中使用相同的列,则Hive将多个表上的联接转换为单个MR作业

      1
      2
      3
      4
      5
      SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
      --由于联接中仅涉及b的key1列,因此被转换为1个MR作业来执行,并且表a和b的键的特定值的值被缓冲在reducer的内存中。然后,对于从c中检索的每一行,将使用缓冲的行来计算联接。
      SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
      --计算涉及两个MR作业。其中的第一个将a与b连接起来,并缓冲a的值,同时在reducer中流式传输b的值。

    • 在join的时候,可以通过语法STREAMTABLE提示指定要流式传输的表。如果省略STREAMTABLE提示,则Hive将流式传输最右边的表

      1
      2
      SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
      --a,b,c三个表都在一个MR作业中联接,并且表b和c的键的特定值的值被缓冲在reducer的内存中。然后,对于从a中检索到的每一行,将使用缓冲的行来计算联接。如果省略STREAMTABLE提示,则Hive将流式传输最右边的表。
    • 如果除一个要连接的表之外的所有表都很小,则可以将其作为仅map作业执行

    1
    2
    SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a JOIN b ON a.key = b.key
    --不需要reducer。对于A的每个Mapper,B都会被完全读取。限制是不能执行FULL / RIGHT OUTER JOIN b。