1. Hive 简介
Apache Hive 是一个构建在 Hadoop 之上的数据仓库基础架构,它提供了数据摘要、查询和分析的功能。Hive 的出现是为了让那些熟悉 SQL 但不太熟悉 Java 编程的用户能够方便地处理存储在 Hadoop 分布式文件系统(HDFS)中的大规模数据。Hive 将结构化的数据文件映射为数据库表,并提供类 SQL 的查询语言 HiveQL,底层会将 HiveQL 语句转换为 MapReduce、Tez 或 Spark 作业执行。
1.1 Hive 的历史与发展
Hive 最初由 Facebook 开发,用于处理海量社交媒体数据。2008 年,Facebook 将 Hive 贡献给 Apache 软件基金会,成为 Apache 顶级项目。随着 Hadoop 生态系统的不断发展,Hive 也在持续演进,引入了诸如 LLAP(Live Long and Process)、ACID 事务、物化视图等特性,使其不仅适用于离线批处理,也逐步支持近实时查询场景。
1.2 Hive 的设计目标
-
可扩展性:Hive 可以处理 PB 级数据,通过 Hadoop 集群的横向扩展能力来应对数据增长。
-
易用性:提供类 SQL 的查询语言,降低使用门槛。
-
灵活性:支持多种数据格式(文本、Parquet、ORC、Avro 等)和数据源(HDFS、HBase 等)。
-
容错性:基于 Hadoop 的容错机制,任务失败可自动重试。
-
扩展性:支持用户自定义函数(UDF)、自定义存储格式等。
1.3 Hive 与关系型数据库的对比
| 数据规模 | PB 级 | GB ~ TB 级 |
| 查询延迟 | 较高(分钟级~小时级) | 低(秒级~毫秒级) |
| 数据更新 | 支持有限(ACID 后支持行级更新) | 支持频繁更新 |
| 索引 | 粗粒度索引(分区、分桶) | 细粒度索引 |
| 执行引擎 | MapReduce/Tez/Spark | 专用执行引擎 |
| 数据格式 | 读时模式(Schema on Read) | 写时模式(Schema on Write) |
2. Hive 架构
Hive 的架构主要由以下几个核心组件构成:
-
用户接口:包括 CLI(命令行界面)、JDBC/ODBC 客户端、Web UI(如 HUE)等。
-
Driver(驱动器):接收用户提交的 HiveQL 语句,进行解析、编译、优化,生成执行计划。
-
Compiler(编译器):将 HiveQL 转换为抽象语法树(AST),然后进行语义分析,最终生成逻辑计划和物理计划。
-
Metastore(元数据存储):存储表的定义、分区信息、列类型等元数据。通常使用关系型数据库(如 MySQL、Derby)来存储。
-
Execution Engine(执行引擎):执行生成的物理计划,可以是 MapReduce、Tez 或 Spark。
-
Hadoop 集群:底层存储(HDFS)和计算资源(YARN)。
2.1 各组件详解
2.1.1 用户接口
-
CLI(Command Line Interface):最常用的交互方式,用户通过 hive 命令进入命令行,执行 HiveQL。
-
JDBC/ODBC:Hive 提供了 HiveServer2 服务,允许客户端通过 JDBC/ODBC 连接,实现与应用程序的集成。
-
Web UI:如 Apache Hive Web UI 或第三方工具 Hue,提供图形化界面。
2.1.2 HiveServer2
HiveServer2 是 Hive 的一个服务,允许多客户端并发提交查询,支持身份验证和授权。它改进了 HiveServer1 的并发处理能力和安全性。
2.1.3 Metastore
Metastore 是 Hive 的核心组件,存储所有表的结构信息。它有三种配置模式:
-
内嵌模式(Embedded):使用 Derby 数据库,仅用于单用户测试。
-
本地模式(Local):Metastore 服务与 Hive 服务运行在同一进程,但使用独立数据库(如 MySQL)存储元数据。
-
远程模式(Remote):Metastore 作为独立服务运行,多个 Hive 客户端通过网络连接,适用于生产环境。
2.1.4 执行引擎
Hive 支持多种执行引擎,可通过 hive.execution.engine 配置:
-
MapReduce:传统执行引擎,适合大型批处理任务,但启动开销大。
-
Tez:基于 YARN 的下一代执行引擎,将 MapReduce 的多个阶段优化为一个 DAG,减少中间数据写入,提高性能。
-
Spark:利用内存计算,适合迭代式查询和交互式分析。
2.1.5 LLAP(Live Long and Process)
LLAP 是 Hive 2.0 引入的增强特性,通过在节点上运行常驻服务,提供缓存、预取和部分查询处理能力,显著降低查询延迟,实现近实时查询。
2.2 Hive 工作流程
用户通过接口提交 HiveQL 查询。
Driver 调用编译器,将查询转换为抽象语法树(AST)。
编译器与 Metastore 通信,获取表、分区等元数据。
编译器生成逻辑计划,并经过优化器进行优化(如谓词下推、分区剪裁等),生成物理计划。
Driver 将物理计划提交给执行引擎(MapReduce/Tez/Spark)执行。
执行引擎访问 HDFS 中的数据,执行计算,返回结果。
结果通过接口返回给用户。
3. Hive 安装与配置
3.1 环境准备
-
Java 1.8 或更高版本
-
Hadoop 集群(HDFS 和 YARN)已部署并运行
-
可选:MySQL 或其他关系数据库用于 Metastore
3.2 下载与解压
从 Apache 官网下载 Hive 稳定版,解压到指定目录:
bash
tar -xzf apache-hive-3.x.x-bin.tar.gz
cd apache-hive-3.x.x
3.3 配置环境变量
编辑 ~/.bashrc 或 /etc/profile,添加:
bash
export HIVE_HOME=/path/to/hive
export PATH=$HIVE_HOME/bin:$PATH
执行 source ~/.bashrc 使生效。
3.4 配置文件
Hive 的主要配置文件位于 $HIVE_HOME/conf 目录:
-
hive-env.sh:设置 Hive 运行环境,如 Hadoop 路径。
-
hive-site.xml:核心配置文件,包括 Metastore 连接、执行引擎等。
3.4.1 配置 Metastore
以 MySQL 为例,需要将 MySQL JDBC 驱动 jar 包放入 $HIVE_HOME/lib 目录,然后在 hive-site.xml 中添加:
xml
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://localhost:3306/hive_metastore?createDatabaseIfNotExist=true</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>hive_user</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>password</value>
</property>
3.4.2 初始化 Metastore
运行 schematool 初始化数据库:
bash
$HIVE_HOME/bin/schematool -initSchema -dbType mysql
3.4.3 其他常用配置
-
hive.execution.engine:执行引擎,可选 mr(默认)、tez、spark。
-
hive.cli.print.header:CLI 是否打印列名。
-
hive.metastore.warehouse.dir:数据仓库在 HDFS 上的根目录,默认 /user/hive/warehouse。
3.5 启动 Hive
-
CLI 模式:直接运行 hive 命令。
-
HiveServer2 模式:启动服务 hiveserver2,然后通过 beeline 连接:
bash
beeline -u jdbc:hive2://localhost:10000
3.6 验证安装
运行简单查询:
sql
CREATE TABLE test (id INT, name STRING);
SHOW TABLES;
4. Hive 数据模型
Hive 中的数据组织方式类似于关系数据库,包括数据库、表、分区、桶等概念。
4.1 数据库(Database)
数据库用于组织表,避免命名冲突。默认数据库为 default。
sql
CREATE DATABASE mydb;
USE mydb;
4.2 表(Table)
Hive 表分为两种类型:
-
内部表(Managed Table):由 Hive 管理数据生命周期,删除表时会同时删除 HDFS 上的数据。
-
外部表(External Table):数据存储在 Hive 外部,删除表仅删除元数据,保留数据。
创建表示例:
sql
— 内部表
CREATE TABLE employees (
id INT,
name STRING,
salary FLOAT
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
— 外部表
CREATE EXTERNAL TABLE external_table (
id INT,
data STRING
)
LOCATION '/data/external';
4.3 分区(Partition)
分区是一种将数据按照某个列的值进行划分的机制,可以显著提高查询性能。分区列不是表中的实际字段,而是虚拟列。
sql
CREATE TABLE sales (
id INT,
amount FLOAT,
date STRING
)
PARTITIONED BY (year INT, month INT);
数据加载时需指定分区:
sql
LOAD DATA LOCAL INPATH '/data/sales_2024_01.csv' INTO TABLE sales PARTITION (year=2024, month=1);
4.4 分桶(Bucket)
分桶是对数据进行更细粒度的划分,基于某列的哈希值将数据分散到多个文件中。分桶可用于抽样和 Map 端连接优化。
sql
CREATE TABLE bucketed_table (
id INT,
name STRING
)
CLUSTERED BY (id) INTO 4 BUCKETS;
4.5 数据存储格式
Hive 支持多种文件格式,常见的有:
-
TEXTFILE:纯文本,默认格式,可读但空间利用率低。
-
SEQUENCEFILE:二进制键值对,压缩效率高。
-
ORC(Optimized Row Columnar):列式存储,支持压缩和索引,性能优异。
-
PARQUET:另一种列式存储,广泛用于 Hadoop 生态。
-
AVRO:支持模式演化,适合数据交换。
创建表时通过 STORED AS 指定格式:
sql
CREATE TABLE orc_table STORED AS ORC AS SELECT * FROM text_table;
4.6 数据加载与导出
-
加载数据:
sql
LOAD DATA [LOCAL] INPATH 'path' [OVERWRITE] INTO TABLE table_name [PARTITION (partcol=val)];
-
插入数据:
sql
INSERT INTO table_name SELECT …;
INSERT OVERWRITE TABLE table_name SELECT …; -
导出数据:
sql
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/output' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' SELECT …;
5. HiveQL 基础
HiveQL 是 Hive 的查询语言,语法与 SQL 类似,但有一些差异。
5.1 数据类型
基本类型
-
整数:TINYINT、SMALLINT、INT、BIGINT
-
浮点数:FLOAT、DOUBLE
-
布尔:BOOLEAN
-
字符串:STRING、VARCHAR、CHAR
-
时间:TIMESTAMP、DATE
复杂类型
-
ARRAY:有序列表,例如 ARRAY<STRING>
-
MAP:键值对,例如 MAP<STRING, INT>
-
STRUCT:字段集合,例如 STRUCT<name:STRING, age:INT>
-
UNION:联合类型
访问复杂类型:
sql
SELECT array_col[0], map_col['key'], struct_col.name FROM table;
5.2 常用 DDL 语句
-
创建数据库:CREATE DATABASE|SCHEMA [IF NOT EXISTS] db_name
-
删除数据库:DROP DATABASE [IF EXISTS] db_name [CASCADE]
-
创建表:如上所示
-
修改表:
sql
ALTER TABLE table_name RENAME TO new_name;
ALTER TABLE table_name ADD COLUMNS (col_name data_type);
ALTER TABLE table_name REPLACE COLUMNS (col_name data_type); -
删除表:DROP TABLE [IF EXISTS] table_name
5.3 常用 DML 语句
-
查询:SELECT … FROM … WHERE … GROUP BY … ORDER BY …
-
插入:INSERT INTO|OVERWRITE TABLE …
-
更新(ACID 表):UPDATE table SET col=val WHERE condition
-
删除(ACID 表):DELETE FROM table WHERE condition
5.4 查询语法进阶
5.4.1 JOIN 操作
Hive 支持内连接、左外连接、右外连接、全外连接、半连接等。
sql
SELECT a.*, b.* FROM table_a a JOIN table_b b ON a.id = b.id;
注意:Hive 在 MapReduce 引擎下,JOIN 通常将最后一张表作为大表进行流式处理,可通过 /*+ STREAMTABLE(b) */ 提示优化。
5.4.2 子查询
Hive 支持在 FROM 子句中使用子查询(派生表),以及 IN/NOT IN、EXISTS/NOT EXISTS 等。
sql
SELECT * FROM (
SELECT id, COUNT(*) cnt FROM table GROUP BY id
) sub WHERE cnt > 10;
5.4.3 排序与聚集
-
ORDER BY:全局排序,会产生一个 reducer,数据量大时较慢。
-
SORT BY:在每个 reducer 内排序,不保证全局顺序。
-
DISTRIBUTE BY:控制数据如何划分到 reducer,常与 SORT BY 配合。
-
CLUSTER BY:相当于 DISTRIBUTE BY + SORT BY 同一列。
示例:
sql
SELECT id, name FROM table DISTRIBUTE BY id SORT BY id DESC;
5.4.4 分桶表查询
对于分桶表,可以使用 TABLESAMPLE 进行抽样:
sql
SELECT * FROM bucketed_table TABLESAMPLE(BUCKET 1 OUT OF 4 ON id);
5.5 HiveQL 与 SQL 的差异
-
Hive 不支持事务(直到 ACID 支持后,部分支持),默认不支持行级更新。
-
Hive 的索引功能较弱,主要依赖分区和分桶。
-
Hive 支持多表插入(Multi-table insert):
sql
FROM source
INSERT INTO target1 SELECT … WHERE condition1
INSERT INTO target2 SELECT … WHERE condition2; -
Hive 支持 LATERAL VIEW 用于将复杂类型(如数组)展开为多行:
sql
SELECT id, item FROM table LATERAL VIEW EXPLODE(items) item_table AS item;
6. Hive 表操作
6.1 创建表详解
创建表时可以指定多种属性,如存储格式、压缩、行格式、SerDe 等。
6.1.1 行格式与 SerDe
SerDe(Serializer/Deserializer)是 Hive 用来序列化和反序列化数据的接口。默认的 SerDe 是 LazySimpleSerDe,适用于文本格式。也可以使用正则表达式 SerDe、JSON SerDe 等。
sql
CREATE TABLE log (
ip STRING,
time STRING,
url STRING
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "([^ ]*) – – \\\\[([^\\\\]]*)\\\\] \\"([^\\"]*)\\""
)
STORED AS TEXTFILE;
6.1.2 存储格式与压缩
在创建表时可以指定压缩算法,或通过 TBLPROPERTIES 设置。
sql
CREATE TABLE compressed_orc
STORED AS ORC
TBLPROPERTIES ("orc.compress"="ZLIB")
AS SELECT …;
6.1.3 表的属性
通过 TBLPROPERTIES 可以设置表的注释、是否支持事务等。
sql
CREATE TABLE t (id INT) TBLPROPERTIES ('comment'='my table', 'transactional'='true');
6.2 修改表结构
-
添加列:ALTER TABLE table ADD COLUMNS (col1 type, col2 type)
-
修改列名/类型/位置:ALTER TABLE table CHANGE old_col new_col type [FIRST|AFTER col]
-
替换所有列:ALTER TABLE table REPLACE COLUMNS (col1 type, …)
6.3 删除与恢复表
-
删除表:DROP TABLE table(内部表会删除数据)
-
清空表:TRUNCATE TABLE table(仅内部表)
-
恢复删除的表(如果开启了 Trash):可通过从 HDFS 回收站恢复数据,并重新创建表指向该位置。
6.4 复制表结构
sql
CREATE TABLE new_table LIKE existing_table;
6.5 数据导入导出
-
使用 IMPORT 和 EXPORT 命令可以在不同 Hive 实例间迁移表。
sql
EXPORT TABLE table TO '/export/path';
IMPORT FROM '/export/path';
7. 分区与分桶
7.1 分区详解
分区是 Hive 优化查询的重要手段。合理的分区策略可以大大减少扫描的数据量。
7.1.1 静态分区
在加载数据时手动指定分区值。
sql
INSERT OVERWRITE TABLE sales PARTITION (year=2024, month=1)
SELECT id, amount, date FROM raw_data WHERE year=2024 AND month=1;
7.1.2 动态分区
Hive 可以根据查询结果自动创建分区。需要开启动态分区:
sql
SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict; — 允许所有分区动态生成
INSERT OVERWRITE TABLE sales PARTITION (year, month)
SELECT id, amount, date, year, month FROM raw_data;
7.1.3 分区修剪
当查询条件中包含分区列时,Hive 会自动只扫描相关分区。例如:
sql
SELECT * FROM sales WHERE year=2024 AND month=1; — 只扫描对应分区目录
7.1.4 分区管理
-
添加分区:ALTER TABLE sales ADD PARTITION (year=2024, month=2) LOCATION '/path/to/data';
-
删除分区:ALTER TABLE sales DROP PARTITION (year=2024, month=2);
-
查看分区:SHOW PARTITIONS sales;
-
修复分区:MSCK REPAIR TABLE sales;(当 HDFS 目录手动添加时,同步元数据)
7.2 分桶详解
分桶是对数据进行更细粒度的划分,通常用于提高抽样效率和 JOIN 性能。
7.2.1 创建分桶表
sql
CREATE TABLE user_bucketed (
user_id INT,
name STRING
)
CLUSTERED BY (user_id) INTO 32 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
注意:分桶列必须是表中的列。
7.2.2 分桶的原理
Hive 通过对分桶列计算哈希,对桶数取模来决定每条记录属于哪个桶。每个桶对应一个文件。
7.2.3 数据加载到分桶表
通常需要开启强制分桶:
sql
SET hive.enforce.bucketing = true; — Hive 2.x 后默认 true
然后通过 INSERT 方式加载数据:
sql
INSERT OVERWRITE TABLE user_bucketed SELECT user_id, name FROM raw_users;
7.2.4 分桶表的查询优势
-
抽样:TABLESAMPLE(BUCKET x OUT OF y) 可以快速获取部分数据。
-
Map 端 JOIN:当两个表的分桶方式一致(分桶列相同、桶数成倍数关系),可以在 Map 阶段直接进行 JOIN,避免 Reduce 阶段,大大提高性能。
7.3 分区与分桶结合
可以将表先分区再分桶,例如:
sql
CREATE TABLE partitioned_bucketed (
id INT,
value STRING
)
PARTITIONED BY (dt STRING)
CLUSTERED BY (id) INTO 16 BUCKETS;
这样每个分区目录下又有多个桶文件,既利用了分区减少扫描,又利用分桶优化 JOIN。
8. Hive 索引
虽然 Hive 的索引功能不如传统数据库强大,但也提供了有限的索引支持,主要用于加速查询。Hive 2.3.0 之后,索引功能被标记为弃用,推荐使用物化视图和 ORC 文件自带的索引(如布隆过滤器、min-max 索引)来优化查询。
8.1 创建索引
sql
CREATE INDEX idx_sales_amount ON TABLE sales (amount)
AS 'COMPACT' WITH DEFERRED REBUILD;
索引类型有:
-
COMPACT:将索引列的值和对应的 HDFS 块 ID 存储在一起。
-
BITMAP:适用于列值较少的情况。
8.2 重建索引
sql
ALTER INDEX idx_sales_amount ON sales REBUILD;
8.3 删除索引
sql
DROP INDEX idx_sales_amount ON sales;
8.4 使用索引
Hive 优化器会自动判断是否使用索引。索引的缺点是需要额外存储空间,并且数据更新后需要重建,维护成本高。
9. Hive 视图与物化视图
9.1 视图
视图是一个逻辑概念,本质是一个保存的查询语句,不存储数据。视图可以简化复杂查询,限制数据访问权限。
9.1.1 创建视图
sql
CREATE VIEW high_salary_emp AS
SELECT id, name, salary FROM employees WHERE salary > 5000;
9.1.2 使用视图
sql
SELECT * FROM high_salary_emp;
9.1.3 修改与删除视图
sql
ALTER VIEW high_salary_emp AS SELECT …;
DROP VIEW high_salary_emp;
9.2 物化视图
物化视图在 Hive 3.0 引入,它实际存储查询结果,可以用于查询加速。当基表数据变化时,物化视图需要刷新。
9.2.1 创建物化视图
sql
CREATE MATERIALIZED VIEW mv_sales_summary
AS
SELECT year, month, SUM(amount) AS total_sales
FROM sales
GROUP BY year, month;
9.2.2 启用自动重写
为了利用物化视图加速查询,需要开启:
sql
SET hive.materializedview.rewriting=true;
当用户查询与物化视图匹配时,Hive 会自动重写查询使用物化视图。
9.2.3 刷新物化视图
sql
ALTER MATERIALIZED VIEW mv_sales_summary REBUILD;
10. Hive 函数
Hive 提供了丰富的内置函数,并支持用户自定义函数(UDF)。
10.1 内置函数分类
-
数学函数:round(), floor(), rand(), abs() 等。
-
字符串函数:concat(), substr(), upper(), length(), split() 等。
-
日期函数:current_date(), year(), month(), datediff(), date_add() 等。
-
条件函数:if(), case when, coalesce(), nullif() 等。
-
聚合函数:count(), sum(), avg(), max(), min(), collect_list(), collect_set() 等。
-
表生成函数:explode(), posexplode(), json_tuple() 等。
10.2 常用函数示例
sql
— 字符串拼接
SELECT concat(first_name, ' ', last_name) FROM employees;
— 条件判断
SELECT id, if(salary>5000, 'high', 'low') FROM employees;
— 使用 case when
SELECT id,
CASE WHEN age < 18 THEN 'child'
WHEN age BETWEEN 18 AND 60 THEN 'adult'
ELSE 'senior'
END AS age_group
FROM persons;
— 聚合 collect_set 去重收集
SELECT dept, collect_set(name) AS names FROM employees GROUP BY dept;
— explode 展开数组
SELECT id, friend FROM table LATERAL VIEW EXPLODE(friends) f AS friend;
10.3 用户自定义函数(UDF)
当内置函数无法满足需求时,可以编写 UDF。UDF 分为三种:
-
UDF:对单行输入产生单行输出。
-
UDAF:聚合函数,多行输入产生单行输出。
-
UDTF:表生成函数,单行输入产生多行输出。
10.3.1 编写 UDF
以 Java 为例,继承 org.apache.hadoop.hive.ql.exec.UDF 并实现 evaluate() 方法。
java
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public class MyUpper extends UDF {
public Text evaluate(Text input) {
if (input == null) return null;
return new Text(input.toString().toUpperCase());
}
}
打包成 jar,然后在 Hive 中添加:
sql
ADD JAR /path/to/myudf.jar;
CREATE TEMPORARY FUNCTION my_upper AS 'com.example.MyUpper';
10.3.2 使用 UDF
sql
SELECT my_upper(name) FROM employees;
10.4 使用 Transform 脚本
Hive 支持通过 TRANSFORM 子句调用外部脚本(如 Python、Perl)处理数据。
sql
SELECT TRANSFORM(id, name)
USING 'python mapper.py'
AS (id, upper_name)
FROM employees;
这种方式适合快速原型开发,但性能不如 UDF。
11. Hive 查询优化
Hive 优化主要围绕减少数据扫描、避免数据倾斜、选择合适的执行引擎等方面。
11.1 分区剪裁
确保查询中尽量使用分区列作为过滤条件,以减少扫描的数据量。
sql
— 不推荐
SELECT * FROM sales WHERE amount > 1000;
— 推荐
SELECT * FROM sales WHERE year=2024 AND month=1 AND amount > 1000;
11.2 列剪裁
只 select 需要的列,避免 SELECT *,减少 IO 和网络传输。
sql
— 不推荐
SELECT * FROM employees;
— 推荐
SELECT id, name FROM employees;
11.3 谓词下推
将过滤条件尽早应用,减少后续处理的数据量。Hive 优化器会自动进行谓词下推,但某些情况需要手动调整。对于 Join,应尽量将过滤条件放在子查询中提前过滤。
11.4 Join 优化
11.4.1 Map Join
当一张表很小(默认小于 25MB)时,可以使用 Map Join 将小表加载到内存中,在 Map 阶段完成 Join,避免 Reduce 阶段。
sql
— 自动转换
SET hive.auto.convert.join=true;
SET hive.mapjoin.smalltable.filesize=25000000;
— 或手动提示
SELECT /*+ MAPJOIN(b) */ a.*, b.* FROM a JOIN b ON a.id = b.id;
11.4.2 Bucket Map Join
如果两个表的分桶方式相同,且桶数成倍数关系,可以使用 Bucket Map Join,避免全表扫描。
sql
SET hive.optimize.bucketmapjoin=true;
SET hive.optimize.bucketmapjoin.sortedmerge=true;
11.4.3 Skew Join
处理数据倾斜,将倾斜的键单独处理。
sql
SET hive.optimize.skewjoin=true;
SET hive.skewjoin.key=100000; — 当某个 key 超过该行数时视为倾斜
11.5 并行执行
Hive 可以将一个查询的多个阶段并行执行,需配置:
sql
SET hive.exec.parallel=true;
SET hive.exec.parallel.thread.number=8;
11.6 执行引擎选择
对于复杂查询,使用 Tez 或 Spark 往往比 MapReduce 更快。可以在会话中设置:
sql
SET hive.execution.engine=tez; — 或 spark
11.7 向量化查询
向量化查询通过一次处理一批数据(而非一行)来提升 CPU 利用率,适用于 ORC 格式。
sql
SET hive.vectorized.execution.enabled=true;
SET hive.vectorized.execution.reduce.enabled=true;
11.8 CBO(基于成本的优化器)
Hive 的 CBO 利用统计信息选择最优执行计划。需要先收集统计信息:
sql
ANALYZE TABLE sales COMPUTE STATISTICS;
ANALYZE TABLE sales COMPUTE STATISTICS FOR COLUMNS;
然后开启 CBO:
sql
SET hive.cbo.enable=true;
SET hive.compute.query.using.stats=true;
11.9 使用 Tez 的优化
-
启用 Tez 的容器重用:SET tez.runtime.io.sort.mb=2048; 等。
-
调整 reducer 数量:SET hive.exec.reducers.bytes.per.reducer=1073741824; (1GB)
11.10 使用 LLAP
LLAP 提供缓存和预取,可以大幅提升交互式查询性能。需配置 LLAP 服务并设置:
sql
SET hive.llap.execution.mode=all;
12. Hive 安全性
Hive 的安全性主要依赖于 Hadoop 的安全机制(Kerberos)以及 Hive 自身的授权模型。
12.1 认证
-
简单认证:默认,基于操作系统用户。
-
Kerberos 认证:生产环境常用,需要配置 Hadoop 和 Hive 支持 Kerberos。
12.2 授权
Hive 支持多种授权模型:
-
基于存储的授权:通过 HDFS 文件权限控制。
-
SQL 标准授权:Hive 0.13 引入,类似于关系数据库的权限管理。
-
基于 Ranger 或 Sentry 的授权:提供细粒度、集中式的权限控制。
12.2.1 SQL 标准授权
需要配置 hive.security.authorization.enabled=true,并设置管理用户。
sql
— 授予权限
GRANT SELECT ON TABLE sales TO USER alice;
GRANT INSERT ON DATABASE mydb TO ROLE analysts;
— 撤销权限
REVOKE SELECT ON TABLE sales FROM USER alice;
12.3 行级和列级安全
通过 Ranger 或 Sentry 可以实现行过滤和列掩码。
12.4 数据加密
Hive 本身不提供加密,但可以依赖 HDFS 的透明加密或对数据文件手动加密。
13. Hive 与 Hadoop 生态系统集成
13.1 Hive 与 HBase
Hive 可以映射 HBase 表,实现对 HBase 数据的 SQL 查询。
sql
CREATE TABLE hbase_table
ROW FORMAT SERDE 'org.apache.hadoop.hive.hbase.HBaseSerDe'
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf:col1,cf:col2")
TBLPROPERTIES ("hbase.table.name" = "hbase_table");
之后即可通过 HiveQL 查询 HBase 数据。
13.2 Hive 与 HDFS
Hive 默认存储数据在 HDFS 上,与 HDFS 紧密集成。
13.3 Hive 与 Spark
Hive 可以使用 Spark 作为执行引擎,也可以通过 Spark SQL 访问 Hive 表(通过 Hive Metastore)。Hive on Spark 需要配置 Spark 相关依赖。
13.4 Hive 与 Flume、Sqoop
-
Flume:可以将实时采集的数据直接写入 Hive 表(通过 HiveSink 或写入 HDFS 然后由 Hive 管理)。
-
Sqoop:用于在关系数据库和 Hive 之间导入导出数据。Sqoop 可以直接将数据导入 Hive 表。
13.5 Hive 与 Oozie
Oozie 可以编排 Hive 脚本作为工作流的一部分,实现定时调度。
13.6 Hive 与 HCatalog
HCatalog 是 Hive 的元数据服务组件,允许其他工具(如 Pig、MapReduce)通过 HCatalog 访问 Hive 元数据,共享表定义。
13.7 Hive 与 Presto / Impala
Presto 和 Impala 是专门用于交互式查询的引擎,它们都可以通过 Hive Metastore 读取元数据,查询 Hive 表,但使用自己的执行引擎,通常比 Hive 更快。
14. Hive 事务与 ACID
从 Hive 0.14 开始,Hive 支持有限的事务(ACID)特性,允许行级插入、更新和删除。这对于需要数据一致性的场景(如流式数据摄取、缓慢变化维度)非常有用。
14.1 支持 ACID 的条件
-
表必须使用 ORC 文件格式。
-
表必须分桶。
-
设置表属性 transactional=true。
-
需要配置 Hive 支持事务(如 hive.support.concurrency、hive.txn.manager 等)。
14.2 创建 ACID 表
sql
CREATE TABLE acid_table (
id INT,
value STRING
)
CLUSTERED BY (id) INTO 4 BUCKETS
STORED AS ORC
TBLPROPERTIES ('transactional'='true');
14.3 事务操作
sql
— 插入
INSERT INTO acid_table VALUES (1, 'a'), (2, 'b');
— 更新
UPDATE acid_table SET value = 'c' WHERE id = 1;
— 删除
DELETE FROM acid_table WHERE id = 2;
— 合并
MERGE INTO acid_table AS t
USING updates AS s ON t.id = s.id
WHEN MATCHED THEN UPDATE SET t.value = s.value
WHEN NOT MATCHED THEN INSERT VALUES (s.id, s.value);
14.4 事务的隔离级别
Hive 目前支持快照隔离级别(Snapshot Isolation),即每个读取操作看到的是事务开始时的数据快照。
14.5 事务的局限性
-
性能开销较大,不适用于所有场景。
-
需要额外的配置和管理(如压缩清理 delta 文件)。
-
不支持所有表格式(仅 ORC)。
15. Hive 性能调优
15.1 内存调优
-
Map 内存:mapreduce.map.memory.mb 和 mapreduce.map.java.opts
-
Reduce 内存:类似
-
JVM 重用:mapreduce.job.jvm.numtasks 可设为 -1 启用 JVM 重用,减少启动开销。
-
Tez 内存配置:通过 tez.container.size 等配置。
15.2 IO 调优
-
压缩:启用中间结果压缩和最终输出压缩,减少 IO。
sql
SET hive.exec.compress.intermediate=true;
SET hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;
SET hive.exec.compress.output=true;
SET mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec; -
合并小文件:通过 hive.merge.mapfiles、hive.merge.mapredfiles 等配置,在任务结束后合并小文件。
15.3 执行引擎调优
-
MapReduce:调整 reducer 数量公式 hive.exec.reducers.bytes.per.reducer。
-
Tez:启用 Tez 的 Grouping、调整 Shuffle 参数。
-
Spark:配置 Spark 的 executor 内存、核心数等。
15.4 查询语句优化
-
避免笛卡尔积。
-
使用 EXPLAIN 命令查看执行计划,分析瓶颈。
-
对于大数据集,使用 SORT BY 而非 ORDER BY 除非需要全局排序。
-
尽量使用本地模式处理小数据集:SET hive.exec.mode.local.auto=true;
15.5 数据倾斜处理
-
使用 hive.groupby.skewindata=true 对 group by 倾斜进行优化。
-
对于 join 倾斜,可以使用 skew join 或手动将倾斜键拆分。
15.6 使用合适的数据格式
ORC 和 Parquet 通常比文本格式快很多,且支持列式存储和压缩。
15.7 矢量化与 CBO
如前所述,启用矢量化执行和 CBO。
16. Hive 常见问题与最佳实践
16.1 常见问题
Q1: 查询慢,怎么办?
-
检查是否扫描了大量数据(分区剪裁、列剪裁)。
-
查看执行计划,是否存在数据倾斜。
-
考虑使用 Tez/Spark 引擎。
-
确保统计信息最新,启用 CBO。
-
检查是否可以使用 Map Join。
Q2: 数据倾斜如何解决?
-
对于 group by 倾斜,设置 hive.groupby.skewindata=true。
-
对于 join 倾斜,找出倾斜 key,将其单独处理,或者使用 skew join。
-
在业务层面将 null 或特殊值过滤或打散。
Q3: 小文件问题
-
使用 TRUNCATE 清空表后重新插入数据,并设置合并参数。
-
定期运行合并小文件的脚本或使用 ALTER TABLE … CONCATENATE(仅对 RCFile 和 SequenceFile)。
-
ORC 表可以使用 ALTER TABLE … COMPACT 'MAJOR' 进行压缩合并。
Q4: 元数据不一致
-
如果手动在 HDFS 中添加/删除分区,运行 MSCK REPAIR TABLE 同步元数据。
-
对于大量分区,可以使用 MSCK REPAIR TABLE table_name ADD PARTITIONS。
16.2 最佳实践
合理设计分区:分区粒度不宜过细,避免过多小文件。通常按日期分区。
使用 ORC 格式:ORC 提供高压缩比和快速查询。
定期收集统计信息:使 CBO 做出正确决策。
谨慎使用笛卡尔积:除非必要,否则避免。
控制输出文件数:通过调整 reducer 数量或使用 DISTRIBUTE BY 来避免小文件。
使用外部表:当数据需要被其他工具共享时,使用外部表。
对频繁查询的字段建立物化视图。
监控并调优 YARN 资源:确保 Hive 作业有足够资源。
使用 Tez 或 Spark:对于复杂查询,性能远优于 MapReduce。
注意 Hive 版本差异:新版本特性可能帮助优化,及时升级。






