Hive 实战
为什么选择 Hive?
Hive 是 Facebook 开源、Apache 维护的基于 Hadoop 的数据仓库工具,也是目前应用最广泛的大数据解决方案之一。
你可以把它想象成一个翻译官:你只需要写熟悉的 SQL,它就能把这些语句“翻译”成 MapReduce、Spark 或 Tez 任务,在分布式集群上跑起来。哪怕你一行 Java 或 Scala 都不会,照样能处理 PB 级别的数据。
Hive 与传统数据库的本质区别
很多新手会把 Hive 当成 MySQL 的平替,其实它们完全是两套东西:
简单记一句:Hive 是分析历史数据的,不是处理在线业务的。
核心特点
- 类 SQL 语法:HiveQL,上手零门槛
- 可扩展性:轻松支持 PB 级别数据
- 灵活存储:Text、ORC、Parquet、Avro 等格式通吃
- 多引擎支持:底层可切换 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 支持 ARRAY、MAP、STRUCT 这些复杂数据类型,配合 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 虽然直观,但读取效率低、压缩差、占用空间大。生产环境强烈建议用 ORC 或 Parquet。
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;
常用函数速查(只列最有用的)
字符串函数
日期函数
聚合与窗口函数
完整函数列表可查阅 Hive 官方文档。
总结
Hive 是大数据分析的经典入门工具,它的核心价值在于用 SQL 屏蔽了分布式计算的复杂性。
本文带你快速过了一遍核心流程:
- 建库建表(重点是外部表和分区表)
- 数据加载与查询
- 复杂类型与 LATERAL VIEW
- 五大性能优化技巧
- 高频函数速查
希望这篇文章能帮你快速上手 Hive!如果觉得有用,欢迎收藏转发。