## Hive实战
### Hive概述
[Hive](https://hive.apache.org/) 是 Facebook 开源的一款基于 Hadoop 的数据仓库工具,目前由 Apache 软件基金会维护,它是应用最为广泛的大数据解决方案。简单的说,Hive 能将 SQL 查询转变为 MapReduce 或 Spark 任务,对 SQL 提供了完美的支持,能够非常方便的实现大数据统计,让不会使用 Java、Scala 语言的人也可以玩转大数据平台和分布式文件系统,实现对数据的存储和处理。
Hive 的主要作用包括:
1. 将结构化的数据文件映射为一张表。
2. 提供类 SQL 的查询语言 HiveQL来操作大规模数据。
3. 底层依赖 Hadoop 的 HDFS 存储和 MapReduce / Spark / Tez 引擎执行任务。
Hive 的特点如下所示:
1. 类 SQL 语法:支持 SQL 查询,降低大数据学习门槛。
2. 可扩展性:能够比较容易的支持 PB 级别数据。
3. 灵活存储:支持多种存储格式(Text、ORC、Parquet、Avro 等)。
4. 可选择的计算引擎:底层执行引擎有 MapReduce、Tez、Spark。
5. 延迟较高:适合离线分析,不适合低延迟 OLTP 查询。
Hive 和传统关系型数据库的对比:
### 环境搭建
#### 准备工作
> **说明**:下面的操作以 Ubuntu 系统为例。
1. 同步时区
```bash
sudo timedatectl set-timezone Asia/Shanghai
```
2. 修改下载源
```bash
sudo mv /etc/apt/sources.list /etc/apt/sources.list.bak
sudo vi /etc/apt/sources.list
```
```shell
# 24.04 /etc/apt/sources.list
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
```
```shell
# 18.04 /etc/apt/sources.list
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
```
3. 安装工具软件
```bash
sudo apt update
sudo apt upgrade
sudo apt install -y vim wget net-tools openssh-server
```
4. 启动 SSH
```bash
sudo systemctl start ssh
sudo systemctl enable ssh
sudo systemctl status ssh
```
5. 配置防火墙
```bash
sudo ufw enable
sudo ufw allow ssh
sudo ufw status
sudo ufw disable
```
6. 准备 Hadoop
```bash
wget https://archive.apache.org/dist/hadoop/common/stable2/hadoop-2.10.2.tar.gz
sudo tar -zxvf hadoop-2.10.2.tar.gz -C /opt
```
7. 准备 Hive
```bash
wget https://archive.apache.org/dist/hive/stable-2/apache-hive-2.3.9-bin.tar.gz
sudo tar -zxvf apache-hive-2.3.9-bin.tar.gz -C /opt
```
#### Java 环境
1. 检查
```bash
java -version
```
2. 搜索
```bash
sudo apt search openjdk
```
3. 安装
```
sudo apt install -y openjdk-8-jdk
```
#### MySQL 环境
1. 安装
```bash
sudo apt install mysql-server
```
2. 配置
```bash
mysql_secure_installation
```
3. 启动
```bash
sudo systemctl enable mysql
sudo systemctl start mysql
sudo systemctl status mysql
```
#### Hadoop 配置
> **提示**:详见 PDF 文档。
#### Hive 配置
> **提示**:详见 PDF 文档。
#### 启动环境
1. 启动 HDFS
```bash
start-dfs.sh
start-yarn.sh
```
2. 启动 Hive
```bash
hive --service metastore &
hive --service hiveserver2 > hiveserver2.log 2> hiveerrors.log &
```
3. 检查端口
```bash
ss -ntl
netstat -ntlp
### 常用命令
| 命令 | 用途说明 |
| -------------------------------------------------- | --------------------------------------------------- |
| `hadoop fs -ls ` | 列出目录内容,类似 Linux `ls` |
| `hadoop fs -ls -R ` | 递归列出目录下所有文件 |
| `hadoop fs -du ` | 显示文件或目录大小(非递归) |
| `hadoop fs -du -s ` | 汇总显示目录总大小 |
| `hadoop fs -du -h ` | 以可读格式(KB/MB/GB)显示文件大小 |
| `hadoop fs -COUNT ` | 统计目录下的文件数、目录数、总字节数 |
| `hadoop fs -mkdir ` | 创建目录 |
| `hadoop fs -mkdir -p ` | 递归创建多级目录 |
| `hadoop fs -rm ` | 删除文件 |
| `hadoop fs -rm -r ` | 递归删除目录 |
| `hadoop fs -copyFromLocal ` | 从本地复制文件到 HDFS |
| `hadoop fs -moveFromLocal ` | 从本地移动文件到 HDFS(复制后删除本地文件) |
| `hadoop fs -copyToLocal ` | 从 HDFS 复制文件到本地 |
| `hadoop fs -moveToLocal ` | 从 HDFS 移动文件到本地(复制后删除 HDFS 文件) |
| `hadoop fs -put ` | 等价于 `-copyFromLocal`,上传文件 |
| `hadoop fs -get ` | 等价于 `-copyToLocal`,下载文件 |
| `hadoop fs -getmerge ` | 合并 HDFS 目录下的文件,保存到本地单一文件 |
| `hadoop fs -cat ` | 输出文件内容到标准输出(适合查看小文件) |
| `hadoop fs -tail ` | 显示文件结尾的部分内容 |
| `hadoop fs -text ` | 以文本方式查看压缩文件(如 Gzip、SequenceFile)内容 |
| `hadoop fs -appENDToFile ` | 将本地文件内容追加到 HDFS 文件末尾 |
| `hadoop fs -cp ` | 在 HDFS 内部复制文件或目录 |
| `hadoop fs -mv ` | 在 HDFS 内部移动/重命名文件或目录 |
| `hadoop fs -chown ` | 修改文件或目录的所有者和用户组 |
| `hadoop fs -chgrp ` | 修改文件或目录所属用户组 |
| `hadoop fs -chmod ` | 修改文件或目录权限,类似 Linux `chmod` |
| `hadoop fs -stat ` | 显示文件或目录状态信息(如大小、修改时间) |
| `hadoop fs -expunge` | 清空 HDFS 垃圾回收站(TrASh) |
| `hadoop fs -checkSUM ` | 计算文件的校验和 |
### 基本语法
1. 删除数据库。
```hive
DROP DATABASE IF EXISTS eshop CASCADE;
```
2. 创建数据库。
```hive
CREATE DATABASE IF NOT EXISTS eshop;
```
3. 切换上下文。
```hive
USE eshop;
```
4. 创建外部表。
```hive
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,
level INT,
extra1 STRING,
extra2 MAP
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
5. 加载数据。
```hive
LOAD DATA LOCAL INPATH '/home/hadoop/data/user_info/user_info.txt' OVERWRITE INTO TABLE dim_user_info;
```
```hive
LOAD DATA INPATH '/user/data/user_info.txt' OVERWRITE INTO TABLE dim_user_info;
```
6. 创建分区表。
```hive
CREATE TABLE IF NOT EXISTS fact_user_trade
(
user_name STRING,
piece INT,
price DOUBLE,
pay_amount DOUBLE,
goods_category STRING,
pay_time BIGINT
)
PARTITIONED BY (dt STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
```
7. 设置动态分区。
```hive
-- 设置使用动态分区
SET hive.exec.dynamic.partition=true;
-- 设置动态分区为非严格模式(严格模式至少要指定一个动态分区列)
SET hive.exec.dynamic.partition.mode=nonstrict;
-- 一次SQL操作最多能创建多少个动态分区(跨节点)
SET hive.exec.max.dynamic.partitions=1000;
-- 每个节点上最多能创建多少个动态分区
SET hive.exec.max.dynamic.partitions.pernode=10000;
```
8. 修复分区。
```hive
MSCK REPAIR TABLE fact_user_trade;
```
9. 数据提取。
```hive
-- 开启本地模式自动判断
SET hive.exec.mode.local.auto=true;
-- 设置MAPREDUCE文件数量
SET hive.exec.mode.local.auto.input.files.max=128;
-- 设置MAPREDUCE文件大小
SET hive.exec.mode.local.auto.input.bytes.max=134217728;
-- 设置Reduce任务个数为1
SET mapreduce.job.reduces=1;
-- 查询北京女用户的姓名取前10个
SELECT user_name
FROM dim_user_info
WHERE city='beijing'
AND sex='female'
LIMIT 10;
-- 查询2019年3月24日购买了food类商品的用户名、购买数量和支付金额(不聚合)
SELECT user_name
, piece
, pay_amount
FROM fact_user_trade
WHERE dt='2019-03-24'
AND goods_category='food';
-- 统计用户 ELLA 在2018年的总支付金额和最近最远两次消费间隔天数
SELECT SUM(pay_amount) AS total
, DATEDIFF(
MAX(FROM_UNIXTIME(pay_time, 'yyyy-MM-dd')),
MIN(FROM_UNIXTIME(pay_time, 'yyyy-MM-dd'))
) AS gap_days
FROM fact_user_trade
WHERE YEAR(dt)='2018'
AND user_name='ELLA';
```
10. 分组聚合。
```hive
-- 查询2019年1月到4月,每个品类有多少人购买,累计金额是多少
SELECT goods_category
, COUNT(DISTINCT user_name) AS total_user
, SUM(pay_amount) AS total_pay
FROM fact_user_trade
WHERE dt BETWEEN '2019-01-01' AND '2019-04-30'
GROUP BY goods_category;
-- 查询2019年4月支付金额超过5万元的用户
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
HAVING SUM(pay_amount) > 50000;
-- 查询2018年购买的商品品类在两个以上的用户数
SELECT COUNT(t.user_name)
FROM (SELECT user_name
, COUNT(DISTINCT goods_category) AS total
FROM fact_user_trade
WHERE YEAR(dt)='2018'
GROUP BY user_name
HAVING COUNT(DISTINCT goods_category)>2) AS t;
-- 查询2019年4月支付金额最多的用户前5名
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;
-- 统计不同年龄段的用户数
SELECT CASE WHEN age < 20 THEN '20岁以下'
WHEN age < 30 THEN '30岁以下'
WHEN age < 40 THEN '40岁以下'
ELSE '40岁以上'
END AS age_seg,
COUNT(DISTINCT user_id) AS total
FROM dim_user_info
GROUP BY CASE WHEN age < 20 THEN '20岁以下'
WHEN age < 30 THEN '30岁以下'
WHEN age < 40 THEN '40岁以下'
ELSE '40岁以上'
END;
-- 统计激活时间在2018年,年龄段在20-30岁、30-40岁的用户婚姻状况
SELECT age_seg,
IF(marriage_status = 1, '已婚', '未婚') AS marriage_status,
COUNT(*) AS total
FROM (SELECT CASE WHEN age < 20 THEN '20岁以下'
WHEN age < 30 THEN '20-30岁'
WHEN age < 40 THEN '30-40岁'
ELSE '40岁以上'
END AS age_seg,
extra2['marriage_status'] AS marriage_status
FROM dim_user_info
WHERE TO_DATE(first_active_time) BETWEEN '2018-01-01' AND '2018-12-31'
) AS t
WHERE age_seg in ('20-30岁', '30-40岁')
GROUP BY age_seg, IF(marriage_status = 1, '已婚', '未婚');
-- 统计每个用户购买过哪些品类的商品
SELECT user_name,
COLLECT_SET(goods_category) AS categories
FROM fact_user_trade
GROUP BY user_name;
-- 将数组拼接成字符串
SELECT user_name
, CONCAT_WS(', ', COLLECT_SET(goods_category)) AS categories
FROM fact_user_trade
GROUP BY user_name;
-- 将数据聚合成映射类型(map)
SELECT user_name
, STR_TO_MAP(CONCAT_WS(',', COLLECT_LIST(CONCAT(goods_category, ':', cnt)))) AS category_cnt_map
FROM (SELECT user_name
, goods_category
, COUNT(*) AS cnt
FROM fact_user_trade
GROUP BY user_name, goods_category) AS t
GROUP BY user_name;
```
11. 数据抽样。
~~~hive
-- 数据抽样
SELECT *
FROM fact_user_trade
WHERE RAND() < 0.1;
SELECT *
FROM fact_user_trade
TABLESAMPLE(BUCKET 1 OUT OF 10 ON user_name);
-- 二进制存储支持(如ORC)
-- SELECT *
-- FROM fact_user_trade
-- TABLESAMPLE(BYTE 100M);
~~~
12. 横向展开。
```hive
-- 创建视图
CREATE OR REPLACE VIEW v_user_categories
AS
SELECT user_name
, COLLECT_SET(goods_category) AS categories
FROM fact_user_trade
WHERE dt BETWEEN '2019-04-01' and '2019-04-30'
GROUP BY user_name;
CREATE OR REPLACE VIEW v_user_categories_map
AS
SELECT user_name
, STR_TO_MAP(CONCAT_WS(',', COLLECT_LIST(CONCAT(goods_category, ':', cnt)))) AS category_cnt_map
FROM (SELECT user_name
, goods_category
, COUNT(*) AS cnt
FROM fact_user_trade
WHERE dt BETWEEN '2019-04-01' AND '2019-04-30'
GROUP BY user_name, goods_category) AS t
GROUP BY user_name;
-- 横向展开数组(array)
SELECT user_name
, category
FROM v_user_categories
LATERAL VIEW EXPLODE(categories) t AS category;
-- 横向展开映射(map)
SELECT user_name
, category
, cnt
FROM v_user_categories_map
LATERAL VIEW EXPLODE(category_cnt_map) t AS category, cnt;
```
### 建表操作
#### 数据类型
Hive 的数据类型大体分为三类:原始类型、复杂类型、嵌套类型。
| 数据类型 | 类型说明 | 使用场景 |
| ------------- | -----------------------------------------------------| ------------- |
| TINYINT | 1 字节有符号整数,取值范围 -128~127。 | |
| SMALLINT | 2 字节有符号整数,取值范围 -32768 ~ 32767。 | |
| INT | 4 字节有符号整数,取值范围 -2147483648~2147483647。 | |
| BIGINT | 8 字节有符号整数,取值范围 -9223372036854775808~9223372036854775807。 | 计数、ID |
| BOOLEAN | 布尔值,TRUE 或者 FALSE。 | |
| FLOAT | 单精度浮点数(4 字节)。 | |
| DOUBLE | 双精度浮点数(8 字节)。 | |
| DECIMAL(P, S) | 高精度小数,P=总位数,S=小数位数。 | 订单金额 |
| STRING | 长度可变字符串 | 文本、JSON |
| CHAR | 固定长度字符串 | |
| VARCHAR | 限定最大长度字符串 | |
| BINARY | 二进制数据 | |
| TIMESTAMP | 时间戳 | 精确到毫秒 |
| DATE | 日期 | |
| INTERVAL | 时间间隔类型 | |
| STRUCT | 和C语言中的结构体类似,`STRUCT` | 玩家行为 |
| MAP | 由键值对构成的元素的集合,`MAP` | 商品属性 |
| ARRAY | 具有相同类型的变量的容器,`ARRAY` | 装备列表 |
复杂类型和嵌套类型的用法如下所示。
```hive
CREATE TABLE complex
(
c1 ARRAY,
c2 MAP,
c3 STRUCT,
c4 STRUCT>>
);
SELECT c1[0]
, c2['key']
, c3.b
, c4.addrs[0].city
FROM complex;
```
Hive 数据类型支持两种转换:
1. 隐式转换:TINYINT → INT → BIGINT → DOUBLE → STRING、FLOAT → DOUBLE。
2. 显示转换:
```hive
SELECT CAST('123' AS INT);
SELECT CAST(3.14159 AS DECIMAL(5,2));
```
#### 表类型
Hive 中的表类型如下所示:
| 表类型 | 定义/创建方式 | 存储位置 | 生命周期 | 特点 | 应用场景 |
| ------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------- | -------------------------------------------- | ------------------------------------------- | --------------------------------- |
| **内部表 (Managed Table)** | `CREATE TABLE t1 (id INT, name STRING); ` | 数据存放在 Hive 仓库目录下 (`/user/hive/warehouse/...`) | **表删除时数据也被删除** | Hive 全权管理元数据和数据 | 临时性数据、实验性数据 |
| **外部表 (External Table)** | `CREATE EXTERNAL TABLE t2 (id INT, name STRING) LOCATION '/data/t2'; ` | 数据存放在用户指定目录 | **表删除时数据保留**,只删除元数据 | 元数据和数据分离,便于共享 | 数据共享、避免误删、数据湖场景 |
| **分区表 (Partitioned Table)** | `CREATE TABLE sales (id INT, amount INT) PARTITIONED BY (dt STRING, region STRING); ` | 每个分区对应一个子目录 | 分区字段不存储在表数据文件里,而作为路径目录 | 提高查询效率(按分区裁剪数据) | 时间序列、地域划分、日志数据 |
| **分桶表 (Bucketed Table)** | `CREATE TABLE users (id INT, name STRING) CLUSTERED BY (id) INTO 8 BUCKETS; ` | 每个分桶对应一个文件 | 分桶数固定 | 数据按哈希分布到桶文件,便于采样、Join 优化 | 等值 Join、大表抽样、数据均衡分布 |
| **临时表 (Temporary Table)** | `CREATE TEMPORARY TABLE tmp (id INT); ` | 仅存在于当前会话内存中 | 会话结束后自动销毁 | 不会落盘,不更新 Hive 元数据 | 临时计算、会话级中间结果 |
| **视图 (View)** | `CREATE VIEW v1 AS SELECT ...; ` | 不存储数据,只存元数据定义 | 与底层表绑定 | 类似虚拟表 | 数据安全、SQL 复用、封装复杂查询 |
#### 修饰符
创建表的时候可以使用的修饰符如下:
| 关键字 | 作用 | 写了时的效果 | **不写时的默认值** |
| ----------------------------------- | ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| **EXTERNAL** | 指定外部表 | `CREATE EXTERNAL TABLE ... LOCATION ...` → 表和数据分离,删表不删数据 | **内部表 (Managed Table)**,删表时数据目录会一起删除 |
| **PARTITIONED BY** | 定义分区字段 | `PARTITIONED BY (dt STRING, city STRING)` → 数据写到子目录 `/table/dt=2025-08-26/city=Beijing/` | **非分区表**,所有数据放在一个目录下 |
| **CLUSTERED BY ... INTO N BUCKETS** | 分桶 | `CLUSTERED BY (user_id) INTO 8 BUCKETS` → 数据按哈希分布到 8 个文件桶 | **不分桶**,数据就是普通文件 |
| **STORED AS** | 文件存储格式 | 常用:`TEXTFILE`、`SEQUENCEFILE`、`ORC`、`PARQUET` | **TEXTFILE**(文本文件) |
| **ROW FORMAT** | 指定行格式和 SerDe | 比如 `ROW FORMAT DELIMITED FIELDS TERMINATED BY ','` 或 `ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.JsonSerDe'` | **LazySimpleSerDe**(默认分隔符 `\001`,就是不可见的 Ctrl+A) |
| **LOCATION** | 指定 HDFS 路径 | `LOCATION '/user/hive/custom_path'` → 表数据存放到自定义路径 | 默认放到 **仓库目录**:`/user/hive/warehouse/.db//` |
| **TBLPROPERTIES/DBPROPERTIES** | 存储一些元数据属性 | `TBLPROPERTIES ('creator'='Hao')` | **空**,除非手动添加 |
| **COMMENT** | 表/字段备注 | `COMMENT '用户交易事实表'` | **空** |
#### ROW FORMAT
| 写法 | 说明 | 常见场景 |
| ------------------------------------------------------------ | ----------------- | ------------------- |
| `ROW FORMAT DELIMITED FIELDS TERMINATED BY ','` | 按分隔符解析 | CSV/TSV/文本 |
| `ROW FORMAT DEFAULT` | 默认格式,同下 | CSV/TSV/文本 |
| `ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.LazySimpleSerDe'` | 默认 SerDe,同上 | 文本表(\001 分隔) |
| `ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'` | 更智能的 CSV 解析 | 有引号/转义的 CSV |
| `ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'` | 用正则匹配行 | 日志类数据 |
| `ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.JsonSerDe'` | JSON 格式解析 | JSON 文件 |
| `ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.AvroSerDe'` | Avro 格式 | JSON + 二进制压缩 |
| `ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.ParquetHiveSerDe'` | Parquet 格式 | Parquet 数据 |
| `ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OrcSerde'` | ORC 格式 | ORC 数据 |
> **说明**:只有使用**非默认格式(CSV/JSON/Regex)** 时才需要显式指定 SERDE。
### 写入数据
| 写入方式 | 示例语法 | 特点 | 适用场景 |
| ------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------- | --------------------------------------- |
| **INSERT INTO** | `INSERT INTO TABLE sales PARTITION (dt='2025-08-26') SELECT * FROM tmp_sales; ` | 向表/分区 **追加数据**,不会覆盖原有内容 | 日常数据追加写入(日志、交易流水) |
| **INSERT OVERWRITE** | `INSERT OVERWRITE TABLE sales PARTITION (dt='2025-08-26') SELECT * FROM tmp_sales; ` | 覆盖目标表/分区的数据(先删后写) | 周期性全量刷新数据(如 T+1 日报、月报) |
| **LOAD DATA** | `LOAD DATA INPATH '/user/hadoop/data.txt' INTO TABLE sales; ` | **移动文件**到 Hive 表目录(不做解析),速度快 | 已有 HDFS 文件直接导入 Hive |
| **LOAD DATA LOCAL** | `LOAD DATA LOCAL INPATH '/home/user/data.txt' INTO TABLE sales; ` | 从 **本地文件系统**拷贝数据到 Hive 表 | 本地临时数据快速导入 |
| **CREATE TABLE AS SELECT (CTAS)** | `CREATE TABLE new_sales AS SELECT * FROM sales WHERE dt='2025-08-26'; ` | 新建表并写入查询结果,一步到位 | 生成中间表/派生表,数据探索 |
| **INSERT + Directory (写 HDFS)** | `INSERT OVERWRITE DIRECTORY '/tmp/export/' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' SELECT * FROM sales; ` | 把查询结果写到 **HDFS 目录**,可指定分隔符/格式 | 数据导出,和其他系统交互 |
| **INSERT + LOCAL Directory (写本地)** | `INSERT OVERWRITE LOCAL DIRECTORY '/home/user/export/' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' SELECT * FROM sales; ` | 把结果写到 **本地目录** | 小规模结果导出,本地分析 |
| **外部表写入 (External Table)** | `CREATE EXTERNAL TABLE ext_sales (...) LOCATION '/data/sales'; ` | 外部表只管理元数据,实际写入依赖 `LOAD DATA`/`INSERT` | 共享数据目录,防止误删 |
| **动态分区写入** | `SET hive.exec.dynamic.partition=true;` `SET hive.exec.dynamic.partition.mode=nonstrict;` `INSERT OVERWRITE TABLE sales PARTITION (dt) SELECT id, amount, dt FROM tmp; ` | 自动根据字段值生成分区目录 | 大规模分区表装载数据 |
### 常用函数
#### 数学函数 (Math Functions)
| 函数 | 说明 | 示例 |
| -------------------------- | ------------------------ | -------------------------- |
| `abs(x)` | 绝对值 | `abs(-10) = 10` |
| `round(x[, d])` | 四舍五入,d 为保留小数位 | `round(3.14159, 2) = 3.14` |
| `floor(x)` | 向下取整 | `floor(3.9) = 3` |
| `ceil(x)` | 向上取整 | `ceil(3.1) = 4` |
| `rand()` | 生成 [0,1) 随机数 | `rand()` |
| `pow(x, y)` / `power(x,y)` | 幂运算 | `pow(2,3) = 8` |
| `sqrt(x)` | 开平方 | `sqrt(16) = 4` |
| `exp(x)` | e^x | `exp(1) ≈ 2.718` |
| `ln(x)` | 自然对数 | `ln(e) = 1` |
| `log10(x)` | 以 10 为底对数 | `log10(100) = 2` |
#### 字符串函数 (String Functions)
| 函数 | 说明 | 示例 |
| ----------------------------------- | ---------------- | ----------------------------------------------- |
| `length(str)` | 字符串长度 | `length('hive') = 4` |
| `upper(str)` | 转大写 | `upper('hive') = HIVE` |
| `lower(str)` | 转小写 | `lower('HIVE') = hive` |
| `concat(str1,str2,…)` | 拼接字符串 | `concat('hive','sql') = hivesql` |
| `concat_ws(sep,str1,str2,…)` | 用分隔符拼接 | `concat_ws('-', 'a','b','c') = a-b-c` |
| `substr(str, start, len)` | 截取子串 | `substr('hive',2,2) = iv` |
| `instr(str, substr)` | 返回子串位置 | `instr('hive','iv') = 2` |
| `split(str, regex)` | 字符串分割成数组 | `split('a,b,c',',') = ['a','b','c']` |
| `regexp_extract(str, pattern, idx)` | 正则提取 | `regexp_extract('abc123','([0-9]+)',1) = 123` |
| `regexp_replace(str, pattern, rep)` | 正则替换 | `regexp_replace('abc123','[0-9]','X') = abcXXX` |
| `trim(str)` | 去掉首尾空格 | `trim(' hi ') = hi` |
| `lpad(str,n,pad)` | 左填充到 n 长度 | `lpad('hi',5,'*') = ***hi` |
| `rpad(str,n,pad)` | 右填充到 n 长度 | `rpad('hi',5,'*') = hi***` |
#### 日期时间函数 (Date & Time Functions)
| 函数 | 说明 | 示例 |
| ---------------------------- | ---------------- | ----------------------------------------------------- |
| `current_date` | 当前日期 | `2025-09-15` |
| `current_timestamp` | 当前时间戳 | `2025-09-15 22:00:00` |
| `unix_timestamp()` | 当前时间戳(秒) | `1694784000` |
| `from_unixtime(ts, fmt)` | 时间戳转字符串 | `from_unixtime(1694784000,'yyyy-MM-dd') = 2025-09-15` |
| `to_date(str)` | 字符串转日期 | `to_date('2025-09-15 22:00:00') = 2025-09-15` |
| `year(dt)` | 提取年 | `year('2025-09-15') = 2025` |
| `month(dt)` | 提取月 | `month('2025-09-15') = 9` |
| `day(dt)` / `dayofmonth(dt)` | 提取日 | `day('2025-09-15') = 15` |
| `hour(ts)` | 提取小时 | `hour('2025-09-15 22:30:00') = 22` |
| `minute(ts)` | 提取分钟 | `minute('2025-09-15 22:30:00') = 30` |
| `second(ts)` | 提取秒 | `second('2025-09-15 22:30:00') = 0` |
| `datediff(dt1,dt2)` | 日期相差天数 | `datediff('2025-09-15','2025-09-10') = 5` |
| `add_months(dt,n)` | 日期加 n 月 | `add_months('2025-09-15',2) = 2025-11-15` |
| `date_add(dt,n)` | 日期加 n 天 | `date_add('2025-09-15',10) = 2025-09-25` |
| `date_sub(dt,n)` | 日期减 n 天 | `date_sub('2025-09-15',10) = 2025-09-05` |
#### 条件函数 (Conditional Functions)
| 函数 | 说明 | 示例 |
| ------------------------------------- | ---------------------- | ------------------------------------------------ |
| `if(cond, t, f)` | 条件判断 | `if(1=1,'yes','no') = yes` |
| `case when ... then ... else ... end` | 多条件判断 | `case when age>18 then 'adult' else 'child' end` |
| `coalesce(x1,x2,...)` | 返回第一个非 NULL 值 | `coalesce(null,'hive','sql') = hive` |
| `nvl(x, y)` | 如果 x 为 NULL,返回 y | `nvl(null,0) = 0` |
#### 聚合函数 (Aggregate Functions)
| 函数 | 说明 | 示例 |
| ----------------- | -------------- | --------------- |
| `count(*)` | 计数 | `count(*)` |
| `sum(x)` | 求和 | `sum(price)` |
| `avg(x)` | 平均值 | `avg(score)` |
| `max(x)` | 最大值 | `max(age)` |
| `min(x)` | 最小值 | `min(age)` |
| `collect_set(x)` | 去重集合 | `['a','b','c']` |
| `collect_list(x)` | 包含重复的集合 | `['a','b','a']` |
#### 类型转换函数 (Type Conversion Functions)
| 函数 | 说明 | 示例 |
| ----------------- | ------------ | -------------------------- |
| `cast(x AS type)` | 类型转换 | `cast('123' as int) = 123` |
| `typeof(x)` | 返回字段类型 | `typeof(123) = int` |
#### 复杂类型函数 (Complex Types)
| 函数 | 说明 | 示例 |
| ---------------------------- | -------------- | ------------------------------------------- |
| `size(array/map)` | 获取大小 | `size(array('a','b')) = 2` |
| `map_keys(map)` | 返回所有 key | `map_keys(map('a',1,'b',2)) = ['a','b']` |
| `map_values(map)` | 返回所有 value | `map_values(map('a',1,'b',2)) = [1,2]` |
| `sort_array(array)` | 数组排序 | `sort_array(array(3,1,2)) = [1,2,3]` |
| `array_contains(array, val)` | 是否包含元素 | `array_contains(array('a','b'),'a') = true` |
#### 窗口函数 (Window Functions)
常用于 **排名、累计计算、分组内计算**。
| 函数 | 说明 | 示例 |
| --------------------- | ------------------------ | ----------------------------------------------------------- |
| `row_number()` | 分组内行号 | `row_number() over(partition by dept order by salary desc)` |
| `rank()` | 排名(有并列,跳跃排名) | `rank() over(order by score desc)` |
| `dense_rank()` | 排名(有并列,不跳跃) | `dense_rank() over(order by score desc)` |
| `lag(col,n,default)` | 往前取第 n 行值 | `lag(salary,1,0) over(order by id)` |
| `lead(col,n,default)` | 往后取第 n 行值 | `lead(salary,1,0) over(order by id)` |
| `first_value(col)` | 分组内第一个值 | `first_value(salary) over(order by id)` |
| `last_value(col)` | 分组内最后一个值 | `last_value(salary) over(order by id)` |
| `sum(col) over(...)` | 窗口内累计和 | `sum(sales) over(partition by region order by month)` |
#### 应用举例
1. `FROM_UNIXTIME`:将时间戳转换成日期
```hive
SELECT FROM_UNIXTIME(pay_time, 'yyyy-MM-dd hh:mm:ss')
FROM fact_user_trade LIMIT 10;
```
3. `DATEDIFF`:计算两个日期的时间差
```Hive
-- 用户首次激活时间与设定参照时间的间隔
SELECT user_name, DATEDIFF('2019-4-1', to_date(firstactivetime))
FROM dim_user_info LIMIT 10;
```
4. `IF`:根据条件返回不同的值
```Hive
-- 不同性别高级等用户数量
SELECT sex
, IF(level > 5, '高', '低') AS level_type
, COUNT(DISTINCT user_id) AS total
FROM dim_user_info
GROUP BY sex, IF(level > 5, '高', '低');
```
4. `SUBSTR`:字符串取子串
```Hive
-- 统计每个月激活的新用户数
SELECT SUBSTR(first_active_time, 1, 7) AS month
, COUNT(DISTINCT user_id) AS total
FROM dim_user_info
GROUP BY substr(first_active_time, 1, 7);
```
6. `GET_JSON_OBJECT`:从 JSON 字符串中取出指定的`key`对应的`value`,如:`GET_JSON_OBJECT(info, '$.first_name')`。
```Hive
-- 统计不同手机品牌的用户数
SELECT GET_JSON_OBJECT(extra1, '$.phonebrand') AS phone
, COUNT(DISTINCT user_id) AS total
FROM user_info
GROUP BY GET_JSON_OBJECT(extra1, '$.phonebrand');
```
> **说明**:MySQL 对应的函数名字叫`JSON_EXTRACT`。
### 分组聚合
| 操作 | 示例语法 | 功能说明 | 结果特点 | 典型应用场景 |
| ----------------- | ------------------------------------------------------------ | ---------------------- | ------------------------------------------- | ------------------------ |
| **GROUP BY** | `SELECT region, product, SUM(amount) FROM sales GROUP BY region, product; ` | 按指定列分组 | 只输出 **一个维度组合** 的聚合 | 单维度或固定组合汇总 |
| **GROUPING SETS** | `SELECT region, product, SUM(amount) FROM sales GROUP BY GROUPING SETS ((region, product), (region), (product), ()); ` | 一次性指定多个分组组合 | 输出指定的 **多个维度组合结果**,可包含总计 | 报表统计时只关心部分组合 |
| **CUBE** | `SELECT region, product, SUM(amount) FROM sales GROUP BY CUBE(region, product); ` | 自动生成所有维度的组合 | 输出 **所有维度组合**(2^n 种) | OLAP 全量多维分析 |
### 抽样操作
| 抽样方式 | 语法示例 | 核心语义 | 是否随机 | 可重复性 | 精度/偏差 | 依赖前提 | 性能与注意点 | 典型用途 |
| ------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------- | -------------- | --------------------------- | ------------------------- | -------------------------------------------- | ------------------------------------------ | ---------------------------- |
| **BUCKET 抽样(物理桶)** | `SELECT * FROM t TABLESAMPLE(BUCKET 2 OUT OF 8);` | 选取分桶表的**第2个物理桶**(总8桶) | 否 | 稳定(由分桶写入决定) | 与建表分桶分布一致 | 表必须是 **CLUSTERED BY ... INTO 8 BUCKETS** | 只读命中部分文件,快;但只在**分桶表**可用 | 大表等比例取样/一致性校验 |
| **BUCKET 抽样(逻辑桶)** | `SELECT * FROM t TABLESAMPLE(BUCKET 1 OUT OF 4 ON user_id);` | 按 `hASh(user_id)` 把数据映射到4个逻辑桶,取第1桶 | 伪随机(哈希) | 稳定(同 key 结果一致) | 近似 1/4,受 key 倾斜影响 | 无需分桶表 | 只扫命中行;分布受 key 倾斜影响 | 训练/评估集一致切分、AB 分流 |
| **概率抽样(Bernoulli)** | `SELECT * FROM t WHERE RAND() < 0.1;` | 按 10% 概率独立抽取每行 | 是 | 可用 `RAND(42)` 固定种子 | 期望10%,小样本波动大 | 无 | 全表扫描;易受数据量影响 | 快速下采样、探索性分析 |
| **按组固定样本数** | `SELECT * FROM (SELECT *, ROW_NUMBER() OVER(PARTITION BY gid ORDER BY RAND()) rn FROM t) x WHERE rn ≤ 100;` | 每组(`gid`)随机取 **固定 N 条** | 是 | 可用 `RAND(42)` | 各组样本量严格相等 | 需支持窗口函数 | 两次扫描+排序,成本中等 | 类均衡采样、按省份/品类取样 |
| **每组比例抽样** | `WHERE RAND() < CASE WHEN gid='A' THEN 0.2 ELSE 0.05 END` | 按组设定不同抽样率 | 是 | 可固定种子 | 期望比例,组内波动 | 无 | 全表扫描 | 不同业务线/权重抽样 |
| **LIMIT 截取(非随机)** | `SELECT * FROM t LIMIT 1000;` | 取前 N 行(非随机) | 否 | 稳定(受文件/分片顺序影响) | 有偏(非随机) | 无 | 最快;仅用于调试预览 | 开发调试、字段检查 |
| **每桶/每Reducer取 Top-N(非随机)** | `... DISTRIBUTE BY k SORT BY k LIMIT 100;`(或每组 `ROW_NUMBER`) | 每个分片/组取前 N | 否 | 稳定 | 有偏(按排序规则) | 需分发/排序 | 适合并行 TopN,不是随机抽样 | TopN per group、分片抽取 |
### 排序操作
| 排序方式 | 语法示例 | 核心语义 | Reducer 数 | 是否全局有序 | Shuffle/排序行为 | 性能与注意点 | 典型用途 |
| --------------------------- | --------------------------------------------------------- | ----------------------------------------------- | ---------------------- | --------------------------- | ------------------------------------------ | -------------------------------------------------------- | -------------------------- |
| **ORDER BY** | `SELECT * FROM t ORDER BY ts DESC;` | **全局排序** | **1 个**(单 reducer) | 是 | 所有数据进 1 个 reducer 做总排序 | 最慢;单点瓶颈;大结果易 OOM;适合小结果集或配合 `LIMIT` | 导出小结果、最终展示 |
| **ORDER BY … LIMIT** | `SELECT * FROM t ORDER BY score DESC LIMIT 1000;` | 全局 Top-N | 1 个 | 是 | 仍单 reducer,但 `LIMIT` 可提前剪枝 | 可接受;Top-N 常用写法 | 全局 Top-N |
| **SORT BY** | `SELECT * FROM t SORT BY ts DESC;` | **每个 reducer 内部排序**(局部有序) | 多个 | 否 | Map 输出按 key 分区到多 reducer;各自排序 | 快于 ORDER BY;结果整体**不全局有序** | 大表分片排序、并行导出 |
| **DISTRIBUTE BY** | `SELECT * FROM t DISTRIBUTE BY key;` | 控制**按 key 分发**到 reducer | 多个 | 否 | 相同 key 去同一 reducer;无排序 | 常与 SORT BY 搭配使用 | 为后续聚合/排序分区 |
| **DISTRIBUTE BY + SORT BY** | `SELECT * FROM t DISTRIBUTE BY key SORT BY key, ts DESC;` | **同 key 同分片 + 分片内排序** | 多个 | 否(但**每个 key 内有序**) | 同一 key 的记录在同一 reducer 内按规则有序 | 常用;利于下游 merge/sort-bASed 处理 | 按用户/商品时间序列排序 |
| **CLUSTER BY** | `SELECT * FROM t CLUSTER BY key;` | `DISTRIBUTE BY key` **+ `SORT BY key`(升序)** | 多个 | 否 | 语法糖,**不能指定 ASC/DESC** | 简洁,但排序方向不可控 | 分桶写入/等值 Join 预排序 |
| **分区内排序** | `... WHERE dt='2025-08-26' SORT BY ts;` | 只处理某个分区的数据 | 依配置 | 分区内局部有序 | 同 SORT BY | 缩小数据量显著提速 | 分区数据导出、窗口函数前置 |
### 横向展开
`LATERAL VIEW`是 Hive 里一个非常重要的语法,主要用于和表生成函数(如:`EXPLODE`)结合,把一行数据拆成多行。最常见的应用场景是处理 ARRAY、MAP、 JSON 等类型的字段,也可以实现从宽表到窄表的转换。
| 用法 | 示例语法 | 功能说明 | 典型应用场景 |
| ------------------------------------ | ------------------------------------------------------------ | ------------------------------- | ---------------------- |
| **LATERAL VIEW explode(array)** | `SELECT order_id, item FROM orders LATERAL VIEW explode(items) t AS item; ` | 将数组拆成多行,每个元素一行 | 订单明细、事件埋点 |
| **LATERAL VIEW posexplode(array)** | `SELECT order_id, pos, item FROM orders LATERAL VIEW explode(items) t AS pos, item; ` | 数组拆成多行,同时输出元素下标 | 保留顺序的点击流分析 |
| **LATERAL VIEW explode(map)** | `SELECT user_id, k, v FROM user_tags LATERAL VIEW explode(tags) t AS k, v; ` | Map 拆成多行,得到 (key, value) | 用户标签、属性键值对 |
| **LATERAL VIEW json_tuple(json, …)** | `SELECT log_id, ip, device FROM event_log LATERAL VIEW json_tuple(log_json,'ip','device') t AS ip, device; ` | 从 JSON 中抽取字段并生成列 | 日志解析、半结构化数据 |
| **LATERAL VIEW inline(array)** | `SELECT order_id, col1, col2 FROM orders LATERAL VIEW inline(item_structs) t AS col1,col2; ` | struct 数组展开成多行多列 | 一行存多维属性时拆分 |
| **LATERAL VIEW stack(n, …)** | `SELECT user_id, subject, score FROM user_score LATERAL VIEW stack(3,'math',math,'eng',english,'phy',physics) t AS subject, score; ` | 将多列转为多行 (列转行) | 宽表转长表、UNPIVOT |
### HiveSQL vs. MySQL
| **特性** | **Hive SQL** | **MySQL SQL** | **区别说明** |
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| **表分区** | `PARTITIONED BY`(分区):创建表时使用分区来按某一字段划分数据,能加速查询时的数据筛选。 | 不支持分区。 | Hive可以通过分区将数据分开存储,适合大数据场景。MySQL没有类似的分区机制。 |
| **表分桶** | `CLUSTERED BY`(分桶): 将表数据根据某一字段进行分桶,适合用于大表连接优化。 | 不支持分桶。 | Hive支持通过分桶优化连接操作,MySQL不支持分桶功能。 |
| **存储格式** | `STORED AS`:支持ORC、Parquet等列式存储格式。 | 使用行式存储,如InnoDB。 | Hive支持列式存储格式,优化查询和压缩,而MySQL主要使用行式存储。 |
| **查询引擎** | 支持MapReduce、Tez、Spark等多种执行引擎。 | 仅支持InnoDB引擎。 | Hive的查询可以通过不同的执行引擎(如Tez或Spark)优化执行效率,而MySQL只能使用单一引擎。 |
| **复杂查询支持** | 支持LATERAL VIEW、MAP、ARRAY等复杂数据结构处理。 | 不支持LATERAL VIEW等复杂的数据类型和处理。 | Hive支持更复杂的嵌套查询和复杂数据类型,MySQL不支持类似功能。 |
| **JOIN类型** | 支持MapJoin(Map-side Join):小表加载到内存中进行Map阶段的连接,避免了Shuffle。 | 支持标准的INNER JOIN、LEFT JOIN、RIGHT JOIN、OUTER JOIN等。 | Hive的MapJoin优化可以加速小表与大表的连接操作,而MySQL没有MapJoin这种优化策略。 |
| **自定义函数(UDF)** | 支持用户定义函数(UDF)和用户定义表函数(UDTF)。 | 支持用户定义函数(UDF)和触发器。 | Hive更侧重于自定义函数的灵活性,MySQL则更注重与表操作相关的函数。 |
| **查询优化** | 支持分区裁剪(Partition Pruning)、列裁剪(Column Pruning)、动态分区插入等优化。 | 基于索引的优化,但不支持类似Hive的列裁剪和分区裁剪。 | Hive拥有更多的针对大数据的查询优化机制,而MySQL主要依赖于索引和查询缓存等。 |
| **索引** | 支持`CREATE INDEX`:但通常不建议在Hive中使用索引,性能开销较大。 | 支持`CREATE INDEX`,索引是MySQL查询性能的关键之一。 | Hive中索引的使用相对较少且较为消耗资源,而MySQL通过索引大大提高了查询性能。 |
| **数据类型** | 支持`ARRAY`、`MAP`、`STRUCT`等复杂数据类型。 | 只支持基本数据类型,如`INT`、`VARCHAR`等。 | Hive支持更丰富的数据类型,特别是在处理结构化数据时,MySQL相对简单。 |
| **NULL值处理** | 支持`IS NULL`、`IS NOT NULL`,但有时对NULL值的处理可能与MySQL有所不同,具体行为可能会受到执行引擎的影响。 | 支持`IS NULL`、`IS NOT NULL`,NULL值处理比较一致。 | Hive和MySQL都支持NULL值判断,但在大数据量查询时,Hive的NULL处理可能表现不如MySQL精确。 |
| **聚合函数** | 支持常见的聚合函数(如`SUM()`、`COUNT()`、`AVG()`等),并扩展支持`APPROX_COUNT_DISTINCT()`等近似聚合函数。 | 支持常见的聚合函数(如`SUM()`、`COUNT()`、`AVG()`等)。 | Hive提供了`APPROX_COUNT_DISTINCT()`等高效的近似聚合函数,更适合处理海量数据,而MySQL的聚合函数通常是精确计算的。 |
| **支持子查询** | 支持子查询,但对于大数据集的子查询可能不如MySQL高效,通常需要通过优化(如`MAPJOIN`)来加速。 | 支持子查询,MySQL的子查询优化较好,尤其在小数据量查询时表现优异。 | Hive的子查询在大数据量下性能可能不如MySQL,MySQL对子查询的优化更成熟。 |
| **表创建语法** | Hive创建表时需要指定存储格式、分区、文件格式等,示例如下: | MySQL创建表时,主要关注字段类型、索引等,示例如下: | Hive的表创建更复杂,涉及存储格式和分区等,适用于大数据场景,而MySQL的表创建更加简洁。 |
| **物化视图** | Hive支持创建**物化视图**(Materialized View),在某些情况下可以提升查询性能。 | MySQL不直接支持物化视图,通常通过临时表或应用层缓存实现类似功能。 | Hive提供物化视图,允许预先计算并存储查询结果,从而提高查询效率。MySQL没有原生的物化视图支持。 |
| **查询缓存** | Hive不支持查询缓存,通常通过MapJoin、索引等方式进行性能优化。 | MySQL支持查询缓存,可以缓存常见查询的结果以提高查询效率。 | MySQL具有强大的查询缓存机制,而Hive通常依赖其他优化策略来提高性能。 |
| **字符串函数** | Hive支持字符串函数,如`CONCAT()`, `LENGTH()`, `SUBSTRING()`等。 | MySQL也支持字符串函数,且函数的支持程度较全面。 | Hive和MySQL支持相似的字符串操作,但Hive的字符串处理通常更适合大数据分析应用。 |
| **NULL默认值** | Hive中字段通常不支持为NULL指定默认值,插入数据时通常使用`INSERT INTO`语句。 | MySQL允许在创建表时为字段指定NULL或默认值。 | Hive不直接支持字段默认值,而MySQL允许为字段设置默认值(包括NULL)。 |
### 性能优化
Hive SQL查询性能优化方法有很多种,从表结构设计、查询优化到执行引擎调整等多个方面都有不同的优化方式。
| **优化方法** | **描述** | **适用场景** |
| ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| **分区**(Partitioning) | 将表按某个字段(如日期)进行分区。通过分区裁剪,只扫描符合条件的分区,减少扫描的数据量。 | 当数据量大且查询常根据某个字段(如时间、地区等)过滤时使用。 |
| **分桶**(Bucketing) | 将数据根据某个字段的哈希值分成固定数量的桶。用于优化大表与小表的连接操作,特别是在进行聚合时。 | 当需要高效的连接操作和聚合时,尤其是多次对某列进行操作时。 |
| **列裁剪**(Column Pruning) | 查询时仅选择需要的列,减少不必要的列扫描。 | 当查询中只需要表的部分列时。 |
| **分区裁剪**(Partition Pruning) | 查询时通过裁剪掉不符合条件的分区,只扫描满足条件的分区。 | 当表有分区并且查询包含分区字段的过滤条件时。 |
| **压缩存储格式**(ORC、Parquet) | 使用列式存储格式(如ORC、Parquet),比行式存储格式(如TextFile)更高效,尤其是在读取大量数据时。 | 当表的数据量大,特别是需要快速扫描时。 |
| **MapJoin**(Map-side Join) | 小表与大表连接时,将小表加载到内存中在Map阶段完成连接,避免了Shuffle和Reduce阶段的开销。 | 当小表足够小,能够加载到内存中时,进行小表和大表的连接。 |
| **合适的Join类型** | 使用合适的Join类型(如Sort Merge Join或Bucketed Join)可以优化连接操作的效率。 | 当两张表都根据相同列进行分桶或排序时。 |
| **合理使用Hive执行引擎** | 选择合适的执行引擎(MapReduce、Tez、Spark)可以提高查询效率。例如,Tez或Spark通常比MapReduce更高效。 | 根据数据量和查询类型选择不同的执行引擎。 |
| **使用合适的文件格式** | 选择合适的文件格式(如ORC、Parquet)可以提高存储和读取效率,特别是对于大规模数据操作。 | 需要高效存储和读取时。 |
| **开启动态分区插入** | 通过设置`hive.exec.dynamic.partition=true`,可以实现动态分区插入,避免手动指定每个分区。 | 当数据需要按分区动态插入时,避免手动指定分区。 |
| **减少数据扫描**(推迟计算) | 使用`WHERE`子句避免在执行查询时扫描不必要的数据,尽量在早期阶段过滤数据。 | 当查询中涉及大量数据时,尽量在查询的早期阶段减少扫描的数据量。 |
| **分批次执行** | 对查询结果使用`LIMIT`进行分页查询,或者使用数据抽样(`TABLESAMPLE`)来减少查询的数据量。 | 当数据量过大,且对数据的完整性要求不高时。 |
| **适当使用索引** | 创建索引加速查询,尤其是对常用查询条件的列创建索引。 | 当某些列经常用作查询条件时。 |
| **查询缓存** | 启用Hive的查询缓存,缓存结果集,提高相同查询的效率。 | 当相同的查询频繁执行时。 |
| **减少MapReduce任务数量** | 通过调整`mapreduce.map.memory.mb`和`mapreduce.reduce.memory.mb`等参数,减少MapReduce任务的数量,提升计算效率。 | 当查询中涉及多个复杂的MapReduce任务时。 |
| **合理选择表的存储格式** | 为表选择合适的存储格式,避免存储格式不匹配导致性能问题。比如,ORC和Parquet格式在大数据查询中效率较高。 | 当查询的数据量很大,尤其是在读取和聚合时。 |
| **物化视图**(Materialized View) | 创建物化视图,预先计算并存储查询结果,减少重复计算的开销。 | 当某些查询结果被频繁使用时,使用物化视图来提高查询效率。 |
| **并行执行**(Parallel Execution) | 使用并行执行功能,设置`hive.exec.parallel=true`,可以并行执行多个查询任务,减少执行时间。 | 当需要执行多个查询且能够并行时。 |