Hive 实战

为什么选择 Hive?

Hive 是 Facebook 开源、Apache 维护的基于 Hadoop 的数据仓库工具,也是目前应用最广泛的大数据解决方案之一。

你可以把它想象成一个翻译官:你只需要写熟悉的 SQL,它就能把这些语句“翻译”成 MapReduce、Spark 或 Tez 任务,在分布式集群上跑起来。哪怕你一行 Java 或 Scala 都不会,照样能处理 PB 级别的数据。

Hive 与传统数据库的本质区别

很多新手会把 Hive 当成 MySQL 的平替,其实它们完全是两套东西:

维度HiveMySQL/Oracle
定位数据仓库(OLAP)relational-database(OLTP)
数据量PB 级别GB/TB 级别
延迟高(分钟/小时级)低(毫秒/秒级)
更新不支持行级更新/删除支持
索引弱(通常不推荐用)强(核心性能依赖)

简单记一句:Hive 是分析历史数据的,不是处理在线业务的。

核心特点

  1. 类 SQL 语法:HiveQL,上手零门槛
  2. 可扩展性:轻松支持 PB 级别数据
  3. 灵活存储:Text、ORC、Parquet、Avro 等格式通吃
  4. 多引擎支持:底层可切换 MapReduce、Tez 或 Spark

十分钟快速上手(核心语法速览)

本文假设你已经有了可用的 Hive 环境,安装步骤不在讨论范围。

1. 库操作

这几条语句和传统数据库基本一致,注意 CASCADE 会强制删除该库下所有表:

-- 创建库
CREATE DATABASE IF NOT EXISTS eshop;

-- 切换库
USE eshop;

-- 删除库(慎用 CASCADE,会强制删除库下所有表)
DROP DATABASE IF EXISTS eshop CASCADE;

2. 建表:外部表 vs 分区表

这是 Hive 里最重要的两种表类型,务必理解。

外部表:数据文件通常存放在 HDFS 的某个目录下,删表只删元数据,数据文件原封不动。适合多个应用共用一份数据。

CREATE EXTERNAL TABLE IF NOT EXISTS dim_user_info 
(
  user_id           STRING,
  user_name         STRING, 
  sex               STRING,
  age               INT,
  city              STRING,
  first_active_time STRING,
  extra2            MAP<STRING, STRING>
)
ROW FORMAT DELIMITED 
FIELDS TERMINATED BY '\t'
MAP KEYS TERMINATED BY ':'
STORED AS TEXTFILE;

分区表:按某个字段(最常是日期 dt)将数据分子目录存储。查询时如果带上分区条件,Hive 只会扫描相关文件夹,性能可以提升好几个数量级。

CREATE TABLE IF NOT EXISTS fact_user_trade 
(
  user_name      STRING,
  piece          INT,
  pay_amount     DOUBLE,
  goods_category STRING
)  
PARTITIONED BY (dt STRING)   -- 分区字段
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE;

分区字段不建议从业务数据里取,它本质只是目录名。一般用日期字符串,比如 '2019-04-15'

3. 数据加载与提取

-- 加载本地数据
LOAD DATA LOCAL INPATH '/home/hadoop/data/user.txt' OVERWRITE INTO TABLE dim_user_info;

-- 开启动态分区(必备配置)
SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;

-- 查询:北京女用户前10名
SELECT user_name 
FROM dim_user_info
WHERE city='beijing' AND sex='female'
LIMIT 10;

-- 统计:2019年4月支付金额Top5用户
SELECT user_name, SUM(pay_amount) AS total
FROM fact_user_trade
WHERE dt BETWEEN '2019-04-01' AND '2019-04-30'
GROUP BY user_name
ORDER BY total DESC
LIMIT 5;

是不是和传统 SQL 几乎一样?这就是 Hive 的魅力。


高频利器:复杂类型与 LATERAL VIEW

Hive 支持 ARRAYMAPSTRUCT 这些复杂数据类型,配合 LATERAL VIEW 可以实现“一行转多行”的操作,非常适合对聚合后的数据进行扁平化。

场景:统计每个用户购买过的品类

我们可以先用 COLLECT_SET 把每个用户的品类聚合成数组,再用 EXPLODE 炸开:

-- 第一步:聚合得到每个用户的品类数组
CREATE OR REPLACE VIEW v_user_categories AS
SELECT user_name, COLLECT_SET(goods_category) AS categories
FROM fact_user_trade
GROUP BY user_name;

-- 第二步:LATERAL VIEW + EXPLODE 横向展开数组
SELECT user_name, category
FROM v_user_categories
LATERAL VIEW EXPLODE(categories) t AS category;

如果是 MAP<STRING, INT> 这种键值对,也可以同时展开 Key 和 Value:

SELECT user_name, category, cnt
FROM v_user_category_cnt_map
LATERAL VIEW EXPLODE(category_cnt_map) t AS category, cnt;

LATERAL VIEW 可以理解成“在查询时临时把一行拆成多行”,非常实用。


性能优化:五大核心技巧

Hive 优化涉及方方面面,但掌握下面这五点,足以覆盖 80% 的实际场景。

1. 列式存储:ORC 或 Parquet 是首选

默认的 TextFile 虽然直观,但读取效率低、压缩差、占用空间大。生产环境强烈建议用 ORCParquet

CREATE TABLE ... STORED AS ORC;

-- 或者对已有表进行转换
INSERT OVERWRITE TABLE orc_table SELECT * FROM text_table;

2. 分区裁剪与列裁剪

  • 列裁剪:只 SELECT 需要的列,别偷懒写 SELECT *
  • 分区裁剪WHERE 条件里一定要带上分区字段(如 dt

这两条是最容易被忽视、却收益最高的优化手段。

3. MapJoin:小表Join大表的利器

当一张表小到能完全装进内存时,Hive 可以把它广播到所有 Map 节点,省去代价高昂的 Shuffle 过程。

SELECT /*+ MAPJOIN(dim) */ * 
FROM fact_user_trade fact
JOIN dim_user_info dim ON fact.user_id = dim.user_id;

新版 Hive 通常会自动识别小表并开启 MapJoin,一般无需手动加 Hint,但了解原理总是好的。

4. 控制并行度

-- 设置 Reduce 任务个数(一般让系统自动调整,但可以设上限)
SET mapreduce.job.reduces=10;

不建议写死,容易导致资源浪费或负载不均。

5. 开启动态分区(重要性不亚于前四条)

根据数据内容自动创建分区,ETL 流程中几乎必定用到:

SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;

常用函数速查(只列最有用的)

字符串函数

函数作用示例
substr(str, start, len)截取子串substr('2025-09-15', 1, 7) = '2025-09'
concat_ws(sep, str1, ...)带分隔符拼接concat_ws('-', 'a', 'b') = 'a-b'
split(str, regex)分割成数组split('a,b,c', ',')

日期函数

函数作用示例
from_unixtime(ts, fmt)时间戳转日期from_unixtime(1694784000, 'yyyy-MM-dd')
datediff(dt1, dt2)日期差datediff('2025-09-15', '2025-09-10') = 5
date_add(dt, n)日期加n天date_add('2025-09-15', 10)

聚合与窗口函数

函数作用
collect_set(x)去重聚合为数组
row_number() over(...)分组内排名(不并列)
rank() over(...)分组内排名(并列跳跃)
lag(col, n) over(...)取前n行值

完整函数列表可查阅 Hive 官方文档


总结

Hive 是大数据分析的经典入门工具,它的核心价值在于用 SQL 屏蔽了分布式计算的复杂性

本文带你快速过了一遍核心流程:

  1. 建库建表(重点是外部表和分区表)
  2. 数据加载与查询
  3. 复杂类型与 LATERAL VIEW
  4. 五大性能优化技巧
  5. 高频函数速查

希望这篇文章能帮你快速上手 Hive!如果觉得有用,欢迎收藏转发。