摘要
Hive是一个构建在Hadoop之上的数据仓库工具,本质上是SQL到MapReduce的转换器,适合海量数据的批处理查询。与传统数据库相比,它存储在HDFS上,计算执行依赖MapReduce等,不支持实时操作和完整事务。其架构包括JDBC/ODBC接口、Thrift Server、Web界面、命令行界面、驱动器、解析器、任务计划器、元数据存储、执行器、优化器等组件。Hive的元数据存储可选择外部数据库(推荐MySQL/PostgreSQL)或本地嵌入式数据库。执行引擎可选MapReduce、Tez、Spark等,不同引擎适用不同场景。Hive的数据模型与HBase有区别,两者关系紧密但用途不同。Hive优化设计是提升性能的关键。
1. Hive数仓工具简介
Hive 不是传统意义上的数据库,而是一个构建在 Hadoop 之上的数据仓库工具,它本质上是一个 SQL 到 MapReduce 的转换器。一个类比理解Hive:假设你要查工资统计:
- 传统数据库(如 MySQL) :你像在本地 Excel 表格中查工资,速度快、实时、操作灵活;Hive:你把数据放在一个超大文本仓库(HDFS)中,然后写个 SQL,系统生成 MapReduce 作业,跑几分钟后给你结果。
- Hive不是数据库,但它让你像操作数据库一样操作分布式大数据;它是一个数据仓库工具(Data Warehouse System) ,用于在 Hadoop上进行批量数据分析;Hive 适合海量数据的批处理查询,不适合高并发/实时写入业务。
| 对比项 | Hive | 传统数据库(如 MySQL、Oracle) |
|---|---|---|
| 本质 | 数据仓库工具 / SQL 转换器 | 数据库管理系统 |
| 存储位置 | HDFS(分布式文件系统) | 本地磁盘或SAN |
| 计算执行 | MapReduce / Tez / Spark 等 | 内部存储引擎(如 InnoDB) |
| 是否实时 | ❌ 否,批处理型 | ✅ 支持实时、高并发读写 |
| 是否支持事务 | 基础支持(部分 ACID,从 Hive 3.0) | ✅ 完整事务支持 |
| 查询语言 | HiveQL(类似 SQL) | SQL |
| 使用场景 | 大数据分析、离线报表、数据湖 | OLTP 系统(如订单、支付系统) |
1.1. Hive架构原理
Hive 的架构可以分为以下几个组件:
- 用户接口:包括 CLI、JDBC/ODBC、WEBUI。其中,CLI(command line interface)为 shell 命令行;Hive 中的 Thrift 服务器允许外部客户端通过网络与 Hive 进行交互,类似于 JDBC 或 ODBC 协议。WebGUI 是通过浏览器访问 Hive。
- 元数据(Metastore):用以存储 Hive 中的库、表、列、注释、分区、表属性等信息。默认是存储在 Hive 自带的Derby 数据库中的,企业中一般会通过配置将其存储到MySQL中。
- Driver 驱动程序:Driver 驱动程序包括解析器(SQL Parser)、编译器(Physical Plan)、优化器(Query Optimize)、执行器(Execution)。解析器将 SQL 字符串转换成抽象语法树 AST,并对抽象语法树进行分析,比如判断字段是否存在、类型是否合理等,编译器负责将 AST 编译成逻辑执行计划,并由优化器对逻辑执行计划进行优化,最后由执行器将逻辑执行计划转换为屋里运行计划。
- 执行引擎:Hive 本身是不会处理数据的,而是通过执行引擎来处理。默认的执行引擎就是 MapReduce,但是可以通过配置将执行引擎替换为 Spark、Tez 或者 Presto 等。
- Driver 调用解析器处理 HiveQL 字串,这些字串可能是一条 DDL、DML或查询语句。 编译器将字符串转化为计划(plan)。 计划(plan)仅由元数据操作和HDFS操作组成,元数据操作只包含DDL语句,HDFS操作只包含LOAD语句。
- 对插入和查询而言,策略由 MapReduce 任务中的有向无环图(DAG)组成,具体流程如下。
-
- 解析器(parser):将查询字符串转化为解析树表达式。
- 语义分析器(semantic analyzer):将解析树表达式转换为基于块(block-based)的内部查询表达式, 将输入表的模式(schema)信息从 metastore 中进行恢复。 用这些信息验证列名, 展开 SELECT * 以及类型检查(固定类型转换也包含在此检查中)。
- 逻辑计划生成器(logical plan generator):将内部查询表达式转换为逻辑策略,这些策略由逻辑操作树组成。
- 优化器(optimizer):通过逻辑策略构造多途径并以不同方式重写。
- Hive中的执行器,是将最终要执行的MapReduce程序放到YARN上以一系列Job的方式去执行。
- 优化器的功能如下:
-
- 将多 multiple join 合并为一个 multi-way join;
- 对join、group-by 和自定义的 map-reduce 操作重新进行划分;
- 消减不必要的列;
- 在表扫描操作中推行使用谓词下推;
- 对于已分区的表,消减不必要的分区;
- 在抽样查询中,消减不必要的桶。
- 此外,优化器还能增加局部聚合操作用于处理大分组聚合和增加再分区操作用于处理不对称的分组聚合。
- Hive 的底层存储:
-
- Hive的数据是存储在HDFS上的。
- Hive中的库和表可以看做是对HDFS上数据做的一个映射。
1.2. Hive SQL执行过程:
- 执行查询。Hive接口,如命令行或Web UI发送查询驱动程序(任何数据库驱动程序,如JDBC,ODBC等)来执行。
- 获取计划。在驱动程序帮助下查询编译器,分析查询检查语法和查询计划或查询的要求。
- 获取元数据。编译器发送元数据请求到Metastore(任何数据库)。
- 发送元数据。Metastore发送元数据,以编译器的响应。
- 发送计划。编译器检查要求,并重新发送计划给驱动程序。到此为止,查询解析和编译完成。
- 执行计划。驱动程序发送的执行计划到执行引擎。
- 执行工作。在内部,执行作业的过程是一个MapReduce工作。执行引擎发送作业给JobTracker,在名称节点并把它分配作业到TaskTracker,这是在数据节点。在这里,查询执行MapReduce工作。
- 元数据操作。与此同时,在执行时,执行引擎可以通过Metastore执行元数据操作。
- 获得结果。执行引擎接收来自数据节点的结果。
- 发送结果。执行引擎发送这些结果值给驱动程序。
- 发送结果。驱动程序将结果发送给Hive接口。
1.2.1. Hive的优缺点
优点:
- 用 SQL 化的方式代替了繁琐的 MapReduce 程序
- 开发人员容易上手,减小了开发人员的学习成本
- 支持自定义函数(UDF),方便功能扩展
- 基于 Hadoop 可以实现海量数据分析
- 可以水平扩展
缺点:
- Hive 执行延迟比较高,所以 Hive 适合对离线计算或者对实时性要求不高的场景
- Hive 在小数据集处理方面不占优势
- HQL 表达能力有限
- 迭代计算无法表达
- 调优比较困难,可控制粒度较大
1.3. Hive的数据模型
从数据仓库的角度看,Hive是建立在Hadoop上的数据仓库基础架构,可以方便的ETL操作。Hive没有专门的数据存储格式,也没有为数据建立索引,用于可以非常自由的组织Hive中的表,只需要在创建表的时候定义好表的schema即可。Hive中包含4中数据模型:Tabel、ExternalTable、Partition、Bucket。
- Table:类似与传统数据库中的Table,每一个Table在Hive中都有一个相应的目录来存储数据。例如:一个表t,它在HDFS中的路径为:/user/hive/warehouse/t。
- Partition:类似于传统数据库中划分列的索引。在Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition数据都存储在对应的目录中。例如:t表中包含ds和city两个Partition,则对应于ds=2014,city=beijing的HDFS子目录为:/user/hive/warehouse/t/ds=2014/city=Beijing; 需要注意的是,分区列是表的伪列,表数据文件中并不存在这个分区列的数据。
- Buckets:对指定列计算的hash,根据hash值切分数据,目的是为了便于并行,每一个Buckets对应一个文件。将user列分数至32个Bucket上,首先对user列的值计算hash,比如,对应hash=0的HDFS目录为:/user/hive/warehouse/t/ds=2014/city=Beijing/part-00000;对应hash=20的目录为:/user/hive/warehouse/t/ds=2014/city=Beijing/part-00020。
- External Table指向已存在HDFS中的数据,可创建Partition。Managed Table创建和数据加载过程,可以用统一语句实现,实际数据被转移到数据仓库目录中,之后对数据的访问将会直接在数据仓库的目录中完成。删除表时,表中的数据和元数据都会删除。External Table只有一个过程,因为加载数据和创建表是同时完成。数据是存储在Location后面指定的HDFS路径中的,并不会移动到数据仓库中。
2. Hive常用函数示例
2.1. Hive内置函数示例
2.1.1. 字符串函数
-- 字符串长度
SELECT length('hello'); -- 5
-- 大小写转换
SELECT upper('hello'), lower('HELLO'); -- HELLO, hello
-- 字符串截取
SELECT substr('hivefunction', 1, 4); -- hive
-- 查找子串位置
SELECT instr('hive function', 'fun'); -- 6
-- 去除空格
SELECT trim(' hive '); -- hive
-- 字符串拼接
SELECT concat('hive', '_', 'sql'); -- hive_sql
2.1.2. 数值函数
-- 绝对值
SELECT abs(-12); -- 12
-- 取整
SELECT ceil(3.14), floor(3.14); -- 4, 3
-- 四舍五入
SELECT round(3.14159, 2); -- 3.14
-- 随机数
SELECT rand(); -- 0~1 之间随机小数
2.1.3. 日期函数
-- 当前时间戳
SELECT current_timestamp();
-- 当前日期
SELECT current_date();
-- 日期加减
SELECT date_add('2025-08-18', 7); -- 2025-08-25
SELECT date_sub('2025-08-18', 7); -- 2025-08-11
-- 日期差
SELECT datediff('2025-08-18', '2025-08-01'); -- 17
-- 日期格式化
SELECT from_unixtime(unix_timestamp('2025-08-18', 'yyyy-MM-dd'), 'yyyy/MM/dd');
2.1.4. 条件函数
-- CASE WHEN
SELECT CASE WHEN 1=1 THEN 'yes' ELSE 'no' END; -- yes
-- IF 判断
SELECT if(5 > 3, '大', '小'); -- 大
-- NULL 处理
SELECT nvl(NULL, 'default'); -- default
2.1.5. 集合函数
-- 数组
SELECT size(array(1,2,3)); -- 3
SELECT sort_array(array(3,1,2)); -- [1,2,3]
-- MAP
SELECT map('a',10,'b',20)['a']; -- 10
-- explode 拆分
SELECT explode(array(1,2,3)); -- 1 2 3
2.1.6. JSON 函数(常用)
-- 获取 JSON 字段
SELECT get_json_object('{"name":"Tom","age":18}', '$.name'); -- Tom
-- JSON 转 MAP
SELECT json_tuple('{"name":"Tom","age":18}', 'name', 'age'); -- Tom 18
2.2. Hive自定义函数操作
Hive 内置函数不能满足需求时,就需要编写自定义函数(UDF/UDTF/UDAF),比如解析复杂 JSON、做特殊计算等。这里要区分清楚:
- 编写自定义函数 (UDF/UDTF/UDAF) 必须用 Java(因为 Hive 是基于 Java 实现的) ,在 Hive 页面里只能加载和调用,不能直接写Java代码。
- 但是你可以在 Hive 页面里执行加载 JAR、注册函数、调用函数的 SQL。
2.2.1. Hive 自定义函数类型
Hive 的自定义函数分三类:
- UDF (User Defined Function) :一行输入 → 一行输出(最常见)
- UDAF (User Defined Aggregate Function) :多行输入 → 一行输出(类似 SUM、AVG)
- UDTF (User Defined Table-Generating Function) :一行输入 → 多行/多列输出(类似
explode)
2.2.2. 编写自定义UDF的步骤
- 新建一个 Java 类,继承
org.apache.hadoop.hive.ql.exec.UDF。 - 重写
evaluate(...)方法,实现你的逻辑。 - 打包成 jar,上传到 HDFS 或本地。
- 在 Hive 里
ADD JAR并CREATE FUNCTION注册。 - SQL 中调用。
2.2.3. JSON 解析示例(UDF)
假设我们要写一个 UDF,输入 JSON 字符串,解析某个 key 的值。
package com.example.hive.udf;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
import com.alibaba.fastjson.JSONObject;
public class JsonValueUDF extends UDF {
// 输入 json_str 和 key,返回对应值
public Text evaluate(Text jsonStr, Text key) {
if (jsonStr == null || key == null) {
return null;
}
try {
JSONObject obj = JSONObject.parseObject(jsonStr.toString());
String value = obj.getString(key.toString());
return value == null ? null : new Text(value);
} catch (Exception e) {
return null;
}
}
}
Maven pom.xml 里加 FastJSON 依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
执行:
mvn clean package
得到 hive-udf-1.0.jar。
2.2.4. Hive里加载和使用
-- 添加 jar 包
ADD JAR /path/to/hive-udf-1.0.jar;
-- 注册函数
CREATE FUNCTION get_json_value AS 'com.example.hive.udf.JsonValueUDF';
-- 使用函数
SELECT get_json_value('{"name":"hive","age":30}', 'name'); -- hive
SELECT get_json_value('{"name":"hive","age":30}', 'age'); -- 30
2.2.5. 永久函数与临时函数区别
如果要 跨任务复用,需要在 HiveServer 或 metastore 里注册 永久函数:
CREATE FUNCTION parse_json AS 'com.example.hive.udf.JsonParseUDF'
USING JAR 'hdfs:///user/hive/udf/json-udf.jar';
这样所有任务都能直接使用,不必在每个 SQL 脚本里 ADD JAR。DataWorks SQL 节点只要能访问 HDFS 上的 JAR,就可以执行。
在 Hive 或 DataWorks 中,确实可以在 SQL 脚本里使用临时函数(Temporary Function) ,它的作用域只在当前 Session 或当前任务执行过程中有效,不会注册到 Hive 的全局 FUNCTIONS 里。
-- 1. 添加自定义函数 JAR 包(假设已上传到 HDFS 或 OSS)
ADD JAR hdfs:///user/udf/hive-json-udf.jar;
-- 2. 创建临时函数(仅当前 Session/脚本有效)
CREATE TEMPORARY FUNCTION json_extract AS 'com.example.udf.JsonExtractUDF';
-- 3. 使用临时函数解析 json 数据
SELECT
json_extract('{"name":"Alice","age":25}', '$.name') AS user_name,
json_extract('{"name":"Alice","age":25}', '$.age') AS user_age;
2.3. Hive自定义函数示例
| 类型 | 输入输出 | 作用 | 示例 |
|---|---|---|---|
| UDF函数 | 一行输入 → 一行输出 | 类似 substr()、md5() | md5_udf('hello') |
| UDAF函数 | 多行输入 → 一行输出 | 类似 SUM()、AVG() | str_len_sum(name) |
| UDTF函数 | 一行输入 → 多行输出 | 类似 explode() | split_udtf('a,b,c') |
2.3.1. UDF函数示例
场景:对字符串做 MD5 加密。
package com.example.hive.udf;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
import java.security.MessageDigest;
public class Md5UDF extends UDF {
public Text evaluate(Text input) {
if (input == null) return null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(input.toString().getBytes());
byte[] digest = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
return new Text(sb.toString());
} catch (Exception e) {
return null;
}
}
}
使用方法:
ADD JAR hdfs:///user/hive/udf/md5-udf.jar;
CREATE TEMPORARY FUNCTION md5_udf AS 'com.example.hive.udf.Md5UDF';
SELECT md5_udf('hello world');
2.3.2. UDAF函数示例
场景:计算字符串的长度总和(类似 sum,但针对字符串长度)。
package com.example.hive.udaf;
import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
public class StringLengthSumUDAF extends UDAF {
public static class Evaluator implements UDAFEvaluator {
private int total;
public void init() {
total = 0;
}
public boolean iterate(String value) {
if (value != null) {
total += value.length();
}
return true;
}
public int terminatePartial() {
return total;
}
public boolean merge(Integer other) {
if (other != null) {
total += other;
}
return true;
}
public int terminate() {
return total;
}
}
}
使用方法:
ADD JAR hdfs:///user/hive/udf/string-length-udaf.jar;
CREATE TEMPORARY FUNCTION str_len_sum AS 'com.example.hive.udaf.StringLengthSumUDAF';
SELECT str_len_sum(name) FROM users;
2.3.3. UDTF函数示例
场景:把一个逗号分隔的字符串拆分成多行(类似 explode)。
package com.example.hive.udtf;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspectorFactory;
import java.util.ArrayList;
public class SplitUDTF extends GenericUDTF {
@Override
public StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException {
if (args.length != 1) {
throw new UDFArgumentLengthException("SplitUDTF takes exactly one argument");
}
ArrayList<String> fieldNames = new ArrayList<>();
ArrayList<ObjectInspector> fieldOIs = new ArrayList<>();
fieldNames.add("word");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
}
@Override
public void process(Object[] args) throws HiveException {
if (args[0] == null) return;
String input = args[0].toString();
for (String word : input.split(",")) {
String[] result = new String[]{word};
forward(result);
}
}
@Override
public void close() {}
}
使用方法:
ADD JAR hdfs:///user/hive/udf/split-udtf.jar;
CREATE TEMPORARY FUNCTION split_udtf AS 'com.example.hive.udtf.SplitUDTF';
SELECT split_udtf('a,b,c');
结果:
a
b
c
3. Hive实战经验总结
3.1. Hive和数据库的区别?
由于 Hive 使用了类 SQL 的查询语言,容易将 Hive 理解为数据库。其实从结构上来看,Hive 和数据库除了拥有类似的查询语言,再无类似之处。数据库可以用在 Online 的应用中,但是 Hive 是为数据仓库而设计的,清楚这一点,有助于从应用角度理解 Hive 的特性。
- 查询语言:HQL 和 SQL 只是大部分语法比较相似,并不完全一样。由于 SQL 被广泛的应用在数据仓库中,因此,专门针对 Hive 的特性设计了类 SQL 的查询语言 HQL。熟悉 SQL 开发的开发者可以很方便的使用 Hive 进行开发。
- 数据规模:由于 Hive 建立在集群上并可以利用 MapReduce 进行并行计算,因此可以支持很大规模的数据;而数据库可以支持的数据规模较小。
- 执行引擎:Hive 的执行引擎默认是 MapReduce,但是可以通过配置由 Spark、Flink、Tez、Presto 等代替,而数据库使用的是自己的执行引擎。
- 数据存储:Hive 的数据都是存储在 HDFS 中的,而数据库是将数据保存在本地文件系统或裸设备中。
- 执行速度:Hive 存储的数据量大,在查询数据的时候,通常没有索引,需要扫描整个表;加之Hive 使用 MapReduce 作为执行引擎,这些因素都会导致较高的延迟。而 RDBMS 对数据的访问通常是基于索引的,执行延迟较低。当然这个低是有条件的,即数据规模较小,当数据规模大到超过数据库的处理能力的时候,Hive 的并行计算显然能体现出并行的优势。
- 可扩展:Hive 支持水平扩展,数据库通常支持垂直扩展,对水平扩展不友好。Hive 建立在 Hadoop 之上,其可扩展性与 Hadoop 的可扩展性是一致的(Hadoop 集群规模可以轻松超过 1000 个节点)。而 RDBMS 由于 ACID 语义的严格限制,扩展行非常有限。目前最先进的并行数据库 Oracle 在理论上的扩展能力也只有 100 台左右。
- 数据更新:Hive 对数据更新不友好,数据库支持频繁、快速的数据更新。Hive 是针对数据仓库应用设计的,数据仓库的内容是读多写少的。因此,Hive 中不建议对数据的改写,所有的数据都是在加载的时候确定好的。而 RDBMS 中的数据需要频繁、快速的进行更新。
- 索引:Hive 在加载数据的过程中不会对数据进行任何处理,甚至不会对数据进行扫描,因此也没有对数据中的某些 Key 建立索引。Hive 要访问数据中满足条件的特定值时,需要暴力扫描整个数据,因此访问延迟较高。由于 MapReduce 的引入, Hive 可以并行访问数据,因此即使没有索引,对于大数据量的访问,Hive 仍然可以体现出优势。数据库中,通常会针对一个或者几个列建立索引,因此对于少量的特定条件的数据的访问,数据库可以有很高的效率,较低的延迟。由于数据的访问延迟较高,决定了 Hive 不适合在线数据查询。
3.2. 为什么说Hive是建立在Hadoop之上的呢?
- Hive的数据是存储在 HDFS 上的
- 计算是由 MapReduce 完成的
- 任务调度是由 Yarn 完成的
Hive 的作用是将 HQL 转化为 MapReduce 程序并提交到 Hadoop 集群执行,最早是由 Facebook 开源,用以解决海量结构化日志统计的工具。
3.3. Hive需要将元数据的存储到mysql数据库中?
是的,Hive 的元数据(Metastore)确实需要存储在外部数据库中,包括:
- 数据库(DB)
- 表结构(columns、分区、位置等)
- 分区信息
- 权限信息
- 统计信息等
3.3.1. ✅ 外部数据库(生产环境下推荐MySQL/PostgreSQL)
最常用的是 MySQL、PostgreSQL、Oracle、Derby(开发测试用) 。
- 推荐用 MySQL/PostgreSQL:用于生产环境,稳定可靠,支持多并发。
- 部署方式:Metastore 服务独立部署,多个 HiveServer2 共用一个 Metastore DB。
📌 示例配置(hive-site.xml):
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://localhost:3306/hive_metastore</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>hive</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>hivepassword</value>
</property>
3.3.2. ✅ 本地嵌入式数据库(仅开发/学习)
Hive 默认使用 Apache Derby,是一个轻量级的 Java 嵌入式数据库。
- 优点:简单、开箱即用,适合单人测试学习
- 缺点:不支持并发、不能多个进程同时访问
📌 示例连接:
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:derby:;databaseName=metastore_db;create=true</value>
</property>
3.3.3. ✅ 总结对比:
Hive 本身不存储数据? ✅ 正确。Hive 的数据存放在 HDFS 或对象存储中(如 OSS、S3),元数据才存数据库。
Metastore 一定要独立部署吗? 小型集群可以嵌入式。生产推荐将 Metastore Server 单独部署并设置高可用。
| 元数据存储方式 | 特点 | 适合场景 |
|---|---|---|
| MySQL/PostgreSQL | 高并发、高可靠、集群支持 | ✅生产环境 |
| Derby | 简单、无需配置、单线程访问 | 🚫仅限学习测试 |
3.4. Hive中的生产环境需要指定执行引擎(Execution Engine)?
3.4.1. ✅ MapReduce(默认旧执行器)
- Hive 最早的执行引擎。
- 优点:稳定、成熟,与 Hadoop 原生集成。
- 缺点:慢! 启动慢、运行慢,不适合实时/交互式任务。
🔧 生产中已逐渐淘汰,不推荐。
3.4.2. ✅ Apache Tez(轻量图执行引擎)
- Yahoo 为替代 MapReduce 开发的。
- 与 Hive 集成紧密,支持 DDL/DML/SQL。
- 优点:比 MR 快,支持并行优化。
- Hive 3.x 默认推荐执行引擎。
💡 Tez 是很多传统 Hadoop 集群的默认 Hive 执行器。
3.4.3. ✅ Apache Spark(通用大数据计算引擎)
- 支持 Hive on Spark。
- Spark 会将 HiveQL 转换为 Spark SQL 执行。
- 优点:内存计算快、统一流批处理。
- 缺点:兼容性、调试复杂度略高。
💡 Spark 是数据团队转型计算引擎时的重要选择,尤其适合需要复杂 ETL 或 ML 的场景。
3.4.4. ✅ Apache Flink(实时流计算引擎)
- 理论上可以将 Hive 元数据接入 Flink Table API / SQL。
- 但 Flink 并 不是 Hive 的主流执行引擎。
- 通常 Flink 与 Hive 元数据打通,用于读取 Hive 中的数据或写入 Hive。
🚫 Hive 不能直接用 Flink 执行 HiveQL。
3.4.5. ✅ 各执行器适用场景对比:
| 执行引擎 | 优点 | 适合场景 |
|---|---|---|
| MapReduce | 稳定、成熟 | 老系统、兼容性需求 |
| Tez | 快速、兼容性好、低延迟 | ✅推荐生产执行器(Hive 3) |
| Spark | 快速、内存计算、统一平台 | ETL、大数据处理、ML/AI |
| Flink | 流批一体、低延迟 | 实时分析,不适合直接跑 HiveQL |
3.5. Hive的数据库模型与HBase的数据模型区别?
Hive 的数据库模型与 HBase 不完全一样,它们各自设计初衷和数据模型差异明显,但可以集成使用。下面详细对比和说明:
3.5.1. Hive 的数据库模型
Hive 的数据库模型类似于传统关系型数据库(如 MySQL) ,数据存储:Hive 的数据实际是存储在 HDFS 文件系统中,默认以 TextFile 、 ORC 、 Parquet 等格式存储。抽象出结构化的表结构用于处理大数据:
3.5.1.1. Hive 模型结构:
Hive Database
└── Table
├── Partition(可选)
└── Bucket(可选)
3.5.2. 示例(表结构):
CREATE TABLE user_info (
user_id BIGINT,
name STRING,
age INT
)
PARTITIONED BY (dt STRING)
STORED AS PARQUET;
- Database:逻辑命名空间,用于组织表。
- Table:和 RDBMS 类似,表示一个数据集。
- Partition:将表按列(如日期、地区)水平划分,加快查询。
- Bucket(分桶) :将每个分区数据再 hash 分成多个文件,提高并行处理。
3.5.3. ✅ HBase的数据模型
HBase 属于 NoSQL,基于 Google Bigtable 模型设计,强调稀疏表和列式存储,数据模型完全不同:
3.5.3.1. HBase模型结构:
Table
└── RowKey
└── Column Family
└── Column Qualifier : Value
- RowKey:行主键,唯一标识一行数据。
- Column Family:逻辑列族,必须事先定义。
- Column Qualifier:具体字段名(可动态扩展)。
- Value:实际存储的值。
- Timestamp:多版本控制。
3.5.4. 示例结构(user 表):
RowKey: user_001
└── info:name → "张三"
└── info:age → 30
3.5.5. ✅ Hive与HBase的关系?
- Hive 是一个结构化 SQL 查询层,适合 批量离线分析,数据模型接近关系型数据库。
- HBase 是一个 NoSQL 列式数据库,适合 实时读写存储。
- Hive 可以通过外部表的方式访问 HBase 数据,但它们底层的数据模型差异极大。
虽然 Hive 和 HBase 本质上是不同的数据系统,但Hive 支持通过 Storage Handler 的方式对接 HBase 表,实现:Hive 访问 HBase 表:
CREATE EXTERNAL TABLE hbase_user (
key STRING,
name STRING,
age INT
)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key,info:name,info:age"
)
TBLPROPERTIES (
"hbase.table.name" = "user"
);
- Hive 会将 HBase 表映射成逻辑结构化表。
- 通过 HBase 的 API 实现 CRUD,但是列式 + 非关系型的方式。
- 不支持所有 Hive 功能,如 JOIN、复杂 SQL。
3.5.6. ✅ Hive与HBase对比总结:
| 特性 | Hive | HBase |
|---|---|---|
| 类型 | 数据仓库 / SQL查询引擎 | 分布式 NoSQL 数据库 |
| 数据模型 | 类似 RDBMS 表格结构 | 列式存储、稀疏表 |
| 存储方式 | 存储在 HDFS 文件中 | 存储在 HDFS(HFile) |
| 查询语言 | HiveQL(类 SQL) | HBase API(或 Phoenix SQL) |
| 支持事务 | 不支持或有限支持 | 不支持(需额外组件) |
| 典型用途 | 离线分析、ETL、报表、数仓 | 实时随机读写、高并发 OLTP |
| 连接方式 | 可以访问 HBase 表 | 原生无法访问 Hive 表 |
3.6. Hive和StartRocks的关系?
Hive 和 StarRocks 都是用于 大数据分析场景 的组件,但两者在架构、性能、查询模型、使用方式上有很大不同。下面我们来详细对比:
3.6.1. 🧠 Hive 和 StarRocks 的基本定位
| 组件 | 定位 | 类型 |
|---|---|---|
| Hive | 基于 HDFS 的大数据离线数仓 | 批处理 SQL 引擎 |
| StarRocks | 高性能的 MPP 实时分析数据库 | 实时数仓 / OLAP 引擎 |
3.6.2. 🧱 两者核心架构与特点对比
3.6.2.1. ✅ Hive 特点:
- 基于 Hadoop + HDFS。
- 查询执行使用 MapReduce、Tez、Spark 等引擎(可切换)。
- 面向 离线批处理场景。
- 数据延迟高,一般分钟级 ~ 小时级。
- 查询慢,不支持高并发交互式查询。
- 支持海量存储,数据来源多样。
3.6.2.2. ✅ StarRocks 特点:
- 原生 MPP 架构,C++ 高性能实现。
- 支持 实时写入、秒级查询,适合交互式分析。
- 数据可以通过 Kafka、Flink、Spark、Stream Load、Broker Load等方式导入。
- 高并发,适合数仓中台、BI、大屏系统。
- 支持多种表模型:明细模型、聚合模型、更新模型、主键模型。
- 支持物化视图,极大提升查询效率。
3.6.3. 🔁 Hive 与 StarRocks 的关系与协作
二者通常在一个完整的数据架构中协同使用,不是互相替代,而是取长补短。
3.6.3.1. ✅ 典型关系如下:
| Hive | StarRocks |
|---|---|
| 用于离线数据清洗、聚合、建模 | 用于结果数据的实时查询和快速分析 |
| 存储历史数据(如明细、日志) | 存储处理结果(如宽表、指标) |
| 通过 ETL 或离线任务 写入 StarRocks | 作为 BI、报表系统的数据查询后端 |
| Hive 数据 -> 导入到 StarRocks | 支持通过 Flink 或 Spark Streaming 同步 |
3.6.3.2. ✅ 使用方式举例:
# 场景1:Hive 中建表并处理明细数据
Hive表(ODS) → 清洗 → DWD → DWS层生成宽表
# 场景2:宽表或指标表通过 Flink 或 Spark Load 导入 StarRocks
DWS层的宽表 → Flink CDC → StarRocks → BI工具查询
3.6.4. 💡 使用场景对比
| 场景类型 | Hive 更适合 | StarRocks 更适合 |
|---|---|---|
| 离线大数据批处理 | ✅ | ❌ 不擅长批量计算 |
| 多源异构数据整合 | ✅ 使用 Hive + HDFS | ❌ 通常不是数据汇总的第一步 |
| 实时指标分析 | ❌ 慢、无法满足实时性 | ✅ 支持秒级写入、查询 |
| BI系统交互分析 | ❌ 查询慢、不适合高并发 | ✅ BI 报表、数据大屏秒级响应,支持物化视图 |
| 明细数据建模 | ✅ 可构建 ODS-DWD-DWS-DM 流程 | ❌ 通常只加载最终宽表 |
| 支持更新、删除数据 | ❌ 不支持 DML 语义 | ✅ 支持主键模型和 DELETE、UPDATE |
| 高并发场景 | ❌ Hive 本质是批处理系统 | ✅ 秒级响应、适合并发数千的查询 |