Apache Hive 是构建在 Hadoop 之上的数据仓库工具,它提供了一种类 SQL 的查询语言------HiveSQL(HiveQL),让用户能够以熟悉的 SQL 方式处理存储在 HDFS 或云存储中的大规模数据。本文将系统介绍 HiveSQL 的基本语法结构,并结合实际场景讲解常见的 SQL 写法和最佳实践。
一、HiveSQL 基本语法结构
HiveSQL 的语法设计高度兼容标准 SQL,主要包括以下几个核心部分:
1. 数据定义语言(DDL)
用于创建、修改和删除数据库和表。
创建数据库
CREATE DATABASE IF NOT EXISTS mydata;
USE mydata;
创建表(支持分区、分桶)
CREATE TABLE employees (
emp_id STRING,
name STRING,
age INT,
salary DOUBLE,
dept STRING
)
PARTITIONED BY (dt STRING) -- 按日期分区
CLUSTERED BY (emp_id) INTO 4 BUCKETS -- 分成4个桶
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' -- 字段分隔符
STORED AS TEXTFILE; -- 存储格式
常见存储格式:
TEXTFILE,ORC,PARQUET,AVRO推荐使用 ORC/Parquet 提升性能并节省空间。
修改表结构
-- 添加列
ALTER TABLE employees ADD COLUMNS (email STRING);
-- 修改分区表的分区位置(适用于外部表)
ALTER TABLE logs PARTITION (dt='2024-04-01')
SET LOCATION 's3a://logs/data/20240401';
删除表
DROP TABLE IF EXISTS employees;
2. 数据操作语言(DML)
虽然 Hive 不支持传统意义上的"插入单行",但提供了批量加载和插入功能。
向表中插入数据
-- 插入静态数据
INSERT INTO TABLE employees PARTITION (dt='2024-04-01')
VALUES ('E001', 'Alice', 28, 8000.0, 'HR');
-- 从查询结果插入(最常见用法)
INSERT OVERWRITE TABLE emp_summary
SELECT dept, AVG(salary), COUNT(*)
FROM employees
WHERE dt = '2024-04-01'
GROUP BY dept;
INSERT INTO:追加数据INSERT OVERWRITE:覆盖原有数据(包括分区)
加载本地或 HDFS 文件到表
LOAD DATA LOCAL INPATH '/home/user/data.csv'
INTO TABLE employees
PARTITION (dt='2024-04-01');
注意:
LOCAL表示本地文件系统;不加则为 HDFS 路径。
3. 数据查询语言(DQL)
这是 HiveSQL 使用最频繁的部分,语法与标准 SQL 高度一致。
基础 SELECT 查询
SELECT * FROM employees LIMIT 10;
SELECT emp_id, name, salary FROM employees WHERE age > 25;
条件过滤(WHERE)
SELECT * FROM employees
WHERE dept IN ('HR', 'Tech')
AND salary BETWEEN 5000 AND 10000;
分组统计(GROUP BY)
-- 统计各部门平均薪资
SELECT dept, AVG(salary) AS avg_salary, COUNT(*) AS count
FROM employees
WHERE dt = '2024-04-01'
GROUP BY dept;
排序与排序控制
-- ORDER BY(全局排序,性能低)
SELECT * FROM employees ORDER BY salary DESC LIMIT 10;
-- SORT BY(每个 reducer 内部排序)
SELECT * FROM employees SORT BY salary DESC;
-- DISTRIBUTE BY + SORT BY(组合使用实现分布+排序)
INSERT OVERWRITE DIRECTORY '/output/sorted'
DISTRIBUTE BY dept SORT BY salary DESC
SELECT * FROM employees;
联表查询(JOIN)
-- 内连接
SELECT e.name, d.dept_name
FROM employees e
JOIN departments d ON e.dept = d.dept_id;
-- 左外连接(保留左表所有记录)
SELECT e.name, COALESCE(d.dept_name, '未分配')
FROM employees e
LEFT JOIN departments d ON e.dept = d.dept_id;
Hive 支持:
INNER JOIN,LEFT JOIN,RIGHT JOIN,FULL OUTER JOIN,CROSS JOIN
子查询(Subqueries)
-- 在 FROM 中使用子查询(必须有别名)
SELECT dept, avg_sal
FROM (
SELECT dept, AVG(salary) AS avg_sal
FROM employees
GROUP BY dept
) t
WHERE avg_sal > 7000;
注意:Hive 对子查询的支持较晚版本才完善,建议优先使用 CTE。
公共表表达式(CTE,推荐写法)
WITH high_earners AS (
SELECT emp_id, name, salary FROM employees WHERE salary > 9000
),
dept_stats AS (
SELECT dept, AVG(salary) AS avg_sal FROM employees GROUP BY dept
)
SELECT h.name, h.salary, d.avg_sal
FROM high_earners h
JOIN dept_stats d ON h.dept = d.dept;
二、HiveSQL 特色语法与高级功能
1. 分区裁剪(Partition Pruning)
Hive 会自动跳过无关分区,极大提升查询效率。
-- 只扫描 dt='2024-04-01' 的数据
SELECT * FROM logs WHERE dt = '2024-04-01';
✅ 最佳实践:尽量在 WHERE 条件中指定分区字段。
2. 窗口函数(Window Functions)
Hive 支持多种窗口函数,常用于排名、累计计算等。
-- 按部门对员工薪资进行排名
SELECT
emp_id,
name,
dept,
salary,
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rank_in_dept,
RANK() OVER (ORDER BY salary DESC) AS global_rank,
SUM(salary) OVER (PARTITION BY dept) AS total_dept_salary
FROM employees;
常用窗口函数:
ROW_NUMBER(),RANK(),DENSE_RANK()LEAD(),LAG()------ 获取前后行数据SUM(),AVG(),MIN(),MAX()配合OVER()
3. 条件判断与空值处理
-- CASE WHEN 多条件判断
SELECT
name,
CASE
WHEN salary < 6000 THEN '低薪'
WHEN salary < 9000 THEN '中薪'
ELSE '高薪'
END AS salary_level
FROM employees;
-- 空值处理
SELECT COALESCE(email, '暂无邮箱') FROM employees;
SELECT NVL(phone, '未知') FROM employees;
4. 内置函数(Built-in Functions)
| 类型 | 示例 |
|---|---|
| 字符串 | CONCAT(name, '(', emp_id, ')'), SUBSTR(name, 1, 3) |
| 数学 | ROUND(salary, 2), FLOOR(age / 10) * 10 |
| 日期 | CURRENT_DATE, DATE_ADD(dt, 1), DATEDIFF('2024-04-02', dt) |
| 集合 | SIZE(tags), ARRAY_CONTAINS(hobbies, 'reading') |
三、常用 SQL 写法实战案例
场景 1:每日新增用户统计
INSERT OVERWRITE TABLE daily_new_users PARTITION (dt='${YYYY-MM-DD}')
SELECT
COUNT(*) AS new_user_count,
COUNT(DISTINCT user_id) AS unique_users
FROM user_logs
WHERE dt = '${YYYY-MM-DD}'
AND action = 'register';
场景 2:用户留存率分析(次日留存)
WITH reg_users AS (
SELECT user_id, dt AS reg_date FROM user_logs WHERE action = 'register'
),
active_users AS (
SELECT user_id, dt AS active_date FROM user_logs WHERE action = 'login'
)
SELECT
r.reg_date,
COUNT(*) AS reg_count,
COUNT(a.user_id) AS retained_count,
ROUND(COUNT(a.user_id) * 100.0 / COUNT(*), 2) AS retention_rate
FROM reg_users r
LEFT JOIN active_users a
ON r.user_id = a.user_id
AND a.active_date = DATE_ADD(r.reg_date, 1)
GROUP BY r.reg_date;
场景 3:Top N 每组热门商品
SELECT *
FROM (
SELECT
category,
product_name,
sales,
ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rn
FROM product_sales
) t
WHERE rn <= 3; -- 每类取销量前3的商品
四、HiveSQL 使用建议与注意事项
✅ 推荐做法:
- 使用
ORC或Parquet格式 + 列压缩(Snappy/Zlib) - 合理设计分区(如按天、按地区),避免小文件过多
- 使用 CTE 替代嵌套子查询,提高可读性
- 尽量避免
SELECT *,只选择需要的字段(列裁剪优化) - 开启动态分区:
set hive.exec.dynamic.partition=true;
⚠️ 避免的问题:
- 不要频繁执行小批量 INSERT(易产生小文件)
- 避免笛卡尔积(CROSS JOIN)除非必要
- 不要在生产环境随意运行无 LIMIT 的全表扫描
- 非事务表慎用 UPDATE/DELETE(Hive 3+ 才较好支持)
五、总结
HiveSQL 凭借其类 SQL 的语法、强大的批处理能力和与 Hadoop 生态的深度集成,成为大数据离线分析的主流工具之一。掌握其核心语法和常用写法,不仅能高效完成 ETL 任务,还能支撑复杂的报表和数据分析需求。
通过本文的学习,你应该已经掌握了:
- 如何使用 DDL 创建和管理表
- 如何编写高效的 SELECT 查询
- 如何利用 JOIN、GROUP BY、窗口函数解决实际问题
- 常见的数据分析模式与优化技巧
附录:常用命令速查表
| 功能 | 命令 |
|---|---|
| 查看数据库 | SHOW DATABASES; |
| 查看表 | SHOW TABLES; |
| 查看表结构 | DESCRIBE table_name; 或 DESC table_name; |
| 查看分区 | SHOW PARTITIONS table_name; |
| 设置参数 | SET hive.exec.dynamic.partition=true; |
| 查看当前数据库 | SELECT current_database(); |