初识Hive(2)

一、引言

在上一篇博客中,我们学习了Hive的基础架构、安装搭建以及基础的DDL(数据定义)和DML(数据操作)。我们知道了如何建表、如何加载数据、如何写简单的SQL。

但面对企业级海量数据时,我们会遇到新的问题:

  • 一张表存了几十亿条数据,每次查询都要全表扫描,效率极低怎么办?

  • 文本文件存储占用空间大,读取速度慢,有没有更好的存储格式?

  • 业务需求越来越复杂,需要计算排名、环比、累加和,SQL怎么写?

为了解决这些问题,本篇博客将带你进入Hive的进阶世界。我们将深入学习分区表与分桶表 (优化查询效率)、文件格式与压缩 (优化存储)、复杂查询 (Join与排序),以及Hive中最强大的窗口函数。

二、Hive数据组织方式进阶

2.1 分区表(Partition)------按目录拆分数据

概念 :分区就是把一张大表的数据按照业务需求分散地存储到多个目录,每个目录成为该表的一个分区。查询时通过 WHERE 子句指定分区,可以避免全表扫描。

语法:

sql 复制代码
CREATE TABLE dept_partition(
    deptno INT COMMENT '部门编号',
    dname STRING COMMENT '部门名称',
    loc STRING COMMENT '部门位置'
)
PARTITIONED BY (day STRING COMMENT '天分区字段')
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

基本操作:

sql 复制代码
-- 1. 添加分区
ALTER TABLE dept_partition ADD PARTITION(day='20250830');

-- 2. 删除分区
ALTER TABLE dept_partition DROP PARTITION(day='20250830');

-- 3. 查看分区
SHOW PARTITIONS dept_partition;

-- 4. 修复分区(当HDFS上手动创建了目录,元数据未同步时)
MSCK REPAIR TABLE dept_partition;

二级分区:如果一天的数据量也很大,可以继续按小时拆分:

sql 复制代码
PARTITIONED BY (day STRING, hour STRING)

动态分区 :

向分区表插入数据时,如果不确定有哪些分区,可以让Hive根据数据最后一列的值自动创建分区。

sql 复制代码
-- 开启动态分区并设为非严格模式
SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;

-- 插入数据,最后一个字段 loc 自动作为分区字段
INSERT INTO TABLE dept_partition_dynamic PARTITION(loc)
SELECT deptno, dname, loc FROM dept;

2.2 分桶表(Bucket)------按文件拆分数据

概念 :分区针对的是目录 ,而分桶针对的是文件。分桶是对数据进行更细粒度的划分。Hive会对分桶字段求Hash值,然后对分桶数量取模,结果相同的行写入同一个文件。

语法:

sql 复制代码
CREATE TABLE stu_buck(
    id STRING,
    name STRING,
    age INT
)
CLUSTERED BY(id) INTO 4 BUCKETS  -- 按id分成4个桶
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

分桶排序表:在分桶的基础上,让桶内的数据有序。

sql 复制代码
CLUSTERED BY(id) SORTED BY(id) INTO 4 BUCKETS

三、Hive文件格式与压缩

3.1 存储格式对比

Hive支持多种文件格式,选择合适的格式能大幅提升性能。

格式 类型 特点 适用场景
TextFile 行式存储 默认格式,普通文本,可读性好但压缩率低、查询慢 原始数据、测试
ORC 列式存储 Hive特有,压缩率高,查询极快,支持索引 数仓主流格式
Parquet 列式存储 Hadoop生态通用,兼容性好 Spark/Flink通用

列式存储的优势:查询时只读取需要的列,跳过无关列,极大减少IO。

建表指定格式:

sql 复制代码
STORED AS ORC
-- 或者
STORED AS PARQUET

3.2 数据压缩

大数据场景下,压缩是必选项。常见的压缩算法有 Gzip、Snappy、Lzo 等。

在Hive中配置压缩:

  • TextFile:通过设置参数开启输出压缩。

  • ORC :建表时指定 TBLPROPERTIES("orc.compress"='SNAPPY')。

  • Parquet :建表时指定 TBLPROPERTIES("parquet.compression"='SNAPPY')。

四、Hive复杂查询操作

4.1 基础查询与过滤

sql 复制代码
SELECT * FROM emp WHERE sal > 8000 AND deptno = 30;

4.2 分组与聚合

sql 复制代码
-- 统计每个部门的平均工资,并筛选出平均工资大于4000的部门
SELECT deptno, AVG(sal) AS avg_sal
FROM emp
GROUP BY deptno
HAVING avg_sal > 4000;

注:WHERE 在分组前过滤,不能跟聚合函数;HAVING 在分组后过滤,可以使用聚合函数。

4.3 Join 多表连接

Hive支持标准SQL的连接操作:

sql 复制代码
-- 内连接 (交集)
SELECT e.ename, d.dname FROM emp e JOIN dept d ON e.deptno = d.deptno;

-- 左外连接 (左表全保留)
SELECT e.ename, d.dname FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno;

-- 满外连接 (Hive特有,MySQL不支持)
SELECT e.ename, d.dname FROM emp e FULL JOIN dept d ON e.deptno = d.deptno;

4.4 四大排序机制(重点)

Hive的排序非常讲究,分为以下四种:

排序方式 特点 适用场景
Order By 全局排序,只有一个Reduce,大数据量下极慢 数据量小,需要全局有序
Sort By 局部排序,每个Reduce内部有序,全局无序 数据量大,不需要全局有序
Distribute By 分区,控制数据如何分发到Reduce(Hash) 配合Sort By使用,类似分区分桶
Cluster By 当 Distribute By 和 Sort By 字段相同时的简写,只能升序 简化代码
sql 复制代码
-- 按部门编号分区,每个区内按薪资降序排列
SELECT * FROM emp DISTRIBUTE BY deptno SORT BY sal DESC;

五、Hive内置函数大全

Hive函数分为四大类:单行函数、聚合函数、炸裂函数、窗口函数。

5.1 单行函数(一进一出)

  • 字符串 :substring() 截取、concat_ws() 拼接、regexp_replace() 正则替换、get_json_object() 解析JSON。

  • 日期 :date_add() 加天数、datediff() 日期间隔、date_format() 格式化。

  • 流程控制 :if() 条件判断、CASE WHEN 分支。

5.2 集合函数

Hive支持三种复杂数据类型:array (数组)、map (键值对)、struct (结构体)。

sql 复制代码
-- 创建并访问 map
SELECT map('name','张三', 'age', 18);
SELECT students['name'] FROM test_tbl;

5.3 炸裂函数(UDTF - 一进多出)

explode() 是最常用的炸裂函数,可以将数组或Map中的元素拆分成多行。

典型应用:WordCount(单词统计)与行转列

sql 复制代码
-- 将一行逗号分隔的字符串拆分成多行单词
SELECT explode(split(line, ',')) AS word FROM lines;

-- 配合 LATERAL VIEW 进行侧写展开
SELECT clazz, sex 
FROM clazz_sex 
LATERAL VIEW explode(split(sexs, '|')) T AS sex;

六、Hive的"王炸"------窗口函数

窗口函数是Hive中非常强大的功能。它能为每行数据划分一个"窗口"(计算范围),对窗口内的数据进行计算,然后将结果返回给该行。

基础语法:

sql 复制代码
函数名() OVER (
    [PARTITION BY 分区字段]   -- 分组
    [ORDER BY 排序字段]       -- 排序
    [ROWS | RANGE BETWEEN ... AND ...] -- 窗口范围
)

6.1 窗口范围 (Window Frame)

范围类型 关键字 含义
基于行 ROWS 物理行号。例如 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW 表示上一行到当前行。
基于值 RANGE 逻辑值范围。例如 RANGE BETWEEN 100 PRECEDING AND CURRENT ROW 表示值在(当前值-100)到当前值之间的行。

边界关键字:

  • UNBOUNDED PRECEDING:无边界起点(从第一行开始)

  • CURRENT ROW:当前行

  • UNBOUNDED FOLLOWING:无边界终点(到最后一行)

6.2 常用窗口函数实战

1. 累加求和 / 滑动窗口

sql 复制代码
-- 计算截止到当前日期的总销售额(默认从第一行累加到当前行)
SELECT 
    order_date, 
    order_sal,
    SUM(order_sal) OVER (ORDER BY order_date) AS total_sal
FROM orders;

2. 偏移函数:LAG / LEAD

获取当前行前后第 N 行的值(常用于计算环比、同比)。

sql 复制代码
SELECT 
    order_date,
    -- 获取上一行的日期(如果不存在,默认填1970-01-01)
    LAG(order_date, 1, '1970-01-01') OVER (ORDER BY order_date) AS last_date,
    -- 获取下一行的日期
    LEAD(order_date, 1, '9999-12-31') OVER (ORDER BY order_date) AS next_date
FROM orders;

3. 首尾函数:FIRST_VALUE / LAST_VALUE

获取窗口内第一个或最后一个值。

sql 复制代码
SELECT 
    order_id,
    order_date,
    FIRST_VALUE(order_date, false) OVER (ORDER BY order_date) AS first_date,
    LAST_VALUE(order_date, false) OVER (ORDER BY order_date) AS last_date
FROM emp;

4. 排名函数:RANK / DENSE_RANK / ROW_NUMBER

这是常用的函数。假设有学生成绩:99, 98, 95, 95, 90。

函数 特点 结果 (针对95分)
RANK() 并列跳号 1, 2, 3, 3, 5
DENSE_RANK() 密集排名,并列不跳号 1, 2, 3, 3, 4
ROW_NUMBER() 唯一序号,强行区分,不并列 1, 2, 3, 4, 5
sql 复制代码
SELECT 
    stu_id, 
    score,
    RANK() OVER (ORDER BY score DESC) AS rk,
    DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rk,
    ROW_NUMBER() OVER (ORDER BY score DESC) AS rm
FROM scores;

七、总结

本篇博客从数据存储和查询分析两个维度,深入讲解了Hive的进阶用法:

核心模块 关键知识点
数据组织 分区表(目录)、分桶表(文件)、动态分区
存储优化 ORC / Parquet 列式存储、压缩配置
查询进阶 Group By / Having、Join连接、4种排序机制
内置函数 字符串/日期处理、集合类型、Explode炸裂函数
窗口函数 窗口范围(Rows/Range)、Lag/Lead、Rank/Dense_Rank/Row_Number
相关推荐
skywalk81631 小时前
deepseek对skywalk163/hive 和hivecommons/hive 两个多机AI Agent任务调度项目的对比
人工智能·hive·agent
father_122721 小时前
【ambari管理下hdp2.6.5升级hive1.2.1-2.1.0-2.3.3】
hive·hadoop·ambari
geovindu1 天前
Pivoting and Unpivoting Data in SQL using postgreSQL 18
大数据·数据库·数据仓库·sql·postgresql·数据库开发·数据库架构
数据库小学妹1 天前
OLAP数据库怎么选?看清OLTP、数仓、湖仓边界
数据仓库·mpp·列式存储·联机分析处理·数据库选型·olap数据库
magic_kid_20101 天前
HDFS 故障复盘:千万级 block 导致 FBR 超过 128 MiB,DataNode 被判定为 dead
大数据·hadoop·hdfs·hadoop 故障
小刘在重生~1 天前
Servlet_day2 (上)|Servlet 整合 JDBC|请求转发 forward|Request 作用域
hive·hadoop·servlet
程序 代码狂人2 天前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
天河归来2 天前
从原始消息到业务数据:三层数据架构的设计与实践
数据库·数据仓库·架构