Hive大数据实战指南:从入门到精通

Apache Hive 完整知识总结与使用教程

版本参考 :Apache Hive 4.x / 3.1.x(当前主流生产版本)
官方网站https://hive.apache.org/
官方文档https://cwiki.apache.org/confluence/display/Hive/Home


目录

  1. [Hive 概述](#Hive 概述)
  2. [Hive 核心架构](#Hive 核心架构)
  3. [Hive 数据模型](#Hive 数据模型)
  4. 安装与环境配置
    • 4.1 前置条件
    • 4.2 二进制包安装(传统方式)
    • 4.3 配置 MySQL 作为 Metastore
    • 4.4 启动 Hive 服务
    • 4.5 Docker 快速启动(推荐入门)
  5. [HiveQL DDL 数据定义语言](#HiveQL DDL 数据定义语言)
    • 5.1 数据库操作
    • 5.2 表的创建(内部表 vs 外部表)
    • 5.3 分区表
    • 5.4 分桶表
    • 5.5 表结构修改
    • 5.6 视图(View)
  6. [HiveQL DML 数据操作语言](#HiveQL DML 数据操作语言)
    • 6.1 数据加载(LOAD DATA)
    • 6.2 INSERT 语句
    • 6.3 SELECT 查询详解
    • 6.4 JOIN 操作
    • 6.5 子查询与 CTE
    • 6.6 窗口函数
    • 6.7 ACID 事务(UPDATE / DELETE)
  7. [Hive 数据类型详解](#Hive 数据类型详解)
  8. [Hive 文件格式与存储](#Hive 文件格式与存储)
  9. SerDe(序列化/反序列化)
  10. [Hive 内置函数大全](#Hive 内置函数大全)
  11. [用户自定义函数(UDF / UDAF / UDTF)](#用户自定义函数(UDF / UDAF / UDTF))
  12. [Hive 执行引擎](#Hive 执行引擎)
  13. [Hive 性能调优](#Hive 性能调优)
  14. [Hive 分区管理深入](#Hive 分区管理深入)
  15. [Hive 元数据服务(Metastore)](#Hive 元数据服务(Metastore))
  16. [HiveServer2 与 Beeline](#HiveServer2 与 Beeline)
  17. [Hive 安全机制](#Hive 安全机制)
  18. [Hive 与生态系统集成](#Hive 与生态系统集成)
  19. [Hive 4.x 新特性](#Hive 4.x 新特性)
  20. 常见问题与排查
  21. 最佳实践总结
  22. [Hive 与其他技术对比](#Hive 与其他技术对比)
  23. [附录:配置项速查 & 官方资源](#附录:配置项速查 & 官方资源)

1. Hive 概述

1.1 什么是 Apache Hive?

Apache Hive 是一个构建在 Apache Hadoop 之上的分布式数据仓库软件系统,由 Facebook 于 2007 年开发,后捐献给 Apache 软件基金会。

Hive 的核心价值在于:它提供了类 SQL 的查询语言 HiveQL(HQL),使得熟悉 SQL 的开发者和分析师无需学习 MapReduce 编程即可处理和分析存储在 HDFS 中的海量数据。HiveQL 在底层被自动翻译为 MapReduce、Apache Tez 或 Apache Spark 作业执行。

复制代码
开发者写 HQL 查询 → Hive 编译优化 → 生成 MapReduce/Tez/Spark 作业 → 在 YARN 上执行 → 结果写回 HDFS

1.2 Hive 解决了什么问题?

传统 MapReduce 痛点 Hive 的解法
必须用 Java 编写 MapReduce 程序 HQL(类 SQL),门槛极低
开发周期长,调试困难 声明式查询,框架自动生成执行计划
无法方便地管理结构化数据的 Schema Metastore 统一管理表结构、分区等元数据
缺乏数据发现和数据抽象机制 提供数据仓库级别的抽象:数据库、表、分区、视图
批量数据分析没有统一入口 标准 JDBC/ODBC 接口,BI 工具可直接对接

1.3 Hive 的核心特性

  • SQL 接口:支持 SQL:2003、SQL:2011、SQL:2016 大量标准功能,降低大数据学习门槛
  • 可扩展性:通过 UDF/UDAF/UDTF 支持自定义函数,通过 SerDe 扩展支持的数据格式
  • 多执行引擎:支持 MapReduce、Apache Tez、Apache Spark 作为底层执行引擎
  • 多存储格式:支持 TextFile、ORC、Parquet、Avro、RCFile 等多种文件格式
  • 元数据管理:HMS(Hive Metastore Service)提供集中式元数据存储和管理
  • 分区与分桶:通过分区(Partition)和分桶(Bucketing)优化查询性能
  • ACID 支持:Hive 0.14+ 支持行级 INSERT/UPDATE/DELETE(需 ORC 格式 + 事务配置)
  • Sub-second 查询:通过 LLAP(Live Long and Process)实现交互式亚秒级查询
  • 多云兼容:支持 HDFS、Amazon S3、Azure ADLS、Google Cloud Storage 等存储后端

1.4 Hive 发展历程

版本里程碑 时间 重要变化
Hive 0.x(初始版本) 2008~2012 Facebook 开源,基本 DDL/DML,仅支持 MapReduce
Hive 0.13 2014 原生支持 Parquet 格式
Hive 0.14 2014 ACID 事务支持(UPDATE/DELETE),ORC 格式
Hive 2.0 2016 LLAP(交互式查询),HiveServer2 改进,Hive CLI 弃用
Hive 3.0 2018 移除索引,ACID 默认开启,Druid 集成,去除旧 API
Hive 3.1.x 2019~2022 主流生产版本,稳定性大幅提升
Hive 4.0 2024 JDK 21 支持、Iceberg v3 深度集成、REST Catalog、删除向量
Hive 4.2.0 2025 当前最新版,增强 Iceberg 功能、自动 compaction

1.5 Hive 适用场景 vs 不适用场景

✅ 适用场景:

  • 大规模离线数据仓库(ETL、报表、数据分析)
  • PB 级数据的批量处理
  • 数据湖架构中的结构化查询层
  • BI 工具(Tableau、Power BI 等)通过 JDBC 对接大数据平台
  • 数据迁移和数据质量检查

❌ 不适用场景:

  • 在线事务处理(OLTP):延迟高(秒到分钟级),不适合实时交易
  • 低延迟查询(<100ms 响应):应使用 HBase、Druid、ClickHouse
  • 频繁的小数据量增删改:ACID 支持有限,效率低
  • 实时流数据处理:应使用 Apache Flink 或 Spark Streaming

2. Hive 核心架构

2.1 整体架构图

复制代码
┌──────────────────────────────────────────────────────────────────┐
│                          Client 层                                │
│   CLI(hive shell)  | Beeline(JDBC/ODBC)| Web UI | JDBC/ODBC  │
└───────────────────────────────┬──────────────────────────────────┘
                                │ HQL 查询
                                ▼
┌──────────────────────────────────────────────────────────────────┐
│                       HiveServer2 服务层                          │
│         Thrift Server(处理远程连接,支持多并发认证)               │
└───────────────────────────────┬──────────────────────────────────┘
                                │
         ┌──────────────────────┼──────────────────────┐
         │                      │                      │
         ▼                      ▼                      ▼
   ┌──────────┐           ┌──────────┐           ┌──────────┐
   │  Driver  │           │ Metastore│           │ Compiler │
   │(会话管理)│◄─────────►│(元数据)  │◄─────────►│(查询解析)│
   └──────────┘           └──────────┘           └──────────┘
         │                      │                      │
         │                      ▼                      │
         │           ┌──────────────────┐              │
         │           │ RDBMS(MySQL等)  │              │
         │           │ (持久化元数据)   │              │
         │           └──────────────────┘              │
         │                                             │
         ▼                      ┌────────────────────► │
   ┌──────────┐                 │                      ▼
   │Optimizer │◄────────────────┘              ┌──────────────┐
   │(查询优化)│                                │  Execution   │
   └──────────┘                                │   Engine     │
                                               │  MapReduce / │
                                               │   Tez /Spark │
                                               └──────┬───────┘
                                                      │
                              ┌───────────────────────┤
                              │                       │
                              ▼                       ▼
                         ┌──────────┐           ┌──────────┐
                         │   YARN   │           │   HDFS   │
                         │(资源调度)│           │(数据存储)│
                         └──────────┘           └──────────┘

2.2 核心组件详解

① UI(用户界面)

用户提交 HQL 查询和操作的入口,包括:

  • Hive CLI:命令行工具,已在 Hive 2.0 后被弃用,生产不推荐使用
  • Beeline:基于 JDBC 的客户端 CLI,通过 HiveServer2 连接,推荐使用
  • HWI(Web Interface):Web 界面,已废弃
  • JDBC/ODBC:通过 HiveServer2 对接 BI 工具和应用程序
② Driver(驱动)

负责管理 HQL 语句的完整生命周期:

  • 接收来自 UI 的 HQL 语句
  • 创建和管理 Session Handle(会话句柄)
  • 提供 JDBC/ODBC 兼容接口
  • 协调 Compiler、Optimizer、Executor 的工作
  • 管理执行进度和结果获取
③ Compiler(编译器)

HQL 语句的解析与编译核心:

  1. 词法分析(Lexical Analysis):将 HQL 文本解析为 Token 序列

  2. 语法分析(Parsing) :生成 AST(Abstract Syntax Tree,抽象语法树)

  3. 语义分析(Semantic Analysis):检查表名、列名、数据类型的合法性(查询 Metastore)

  4. 逻辑计划生成(Logical Plan):将 AST 转换为算子树(Operator Tree)

  5. 执行计划生成(Physical Plan) :将逻辑计划转换为 DAG(有向无环图),分解为 MapReduce/Tez/Spark 的 Stage

    HQL 文本 → Token → AST → Operator Tree → DAG of Stages → 物理执行计划

④ Optimizer(优化器)

对编译器生成的执行计划进行变换优化:

  • 谓词下推(Predicate Pushdown):将过滤条件尽早执行,减少数据量
  • 列裁剪(Column Pruning):只读取查询中用到的列
  • 分区裁剪(Partition Pruning):根据分区条件跳过无关分区
  • Join 重排序(Join Reordering):将小表放在 Join 的驱动侧
  • 公共子表达式消除:避免重复计算
  • 使用 CBO(Cost-Based Optimizer):基于统计信息(ANALYZE TABLE)选择最优计划
⑤ Metastore(元数据存储)

Hive 最重要的基础设施之一,存储所有表和分区的元数据

元数据类型 内容
数据库信息 数据库名、描述、HDFS 路径
表信息 表名、列名、数据类型、注释、HDFS 位置、存储格式
分区信息 分区键、分区值、对应 HDFS 路径
SerDe 信息 序列化/反序列化类及属性
统计信息 行数、列的 distinct 值数、最大/最小值等(ANALYZE TABLE 生成)

Metastore 将元数据存储在关系型数据库(默认 Derby,生产用 MySQL/PostgreSQL)中,通过 Thrift 服务对外暴露。

⑥ Execution Engine(执行引擎)

将优化后的执行计划提交给底层计算框架执行:

  • 与 YARN ResourceManager 交互,申请计算资源
  • 监控 Job 执行进度
  • 处理 Task 失败重试
  • 支持 MapReduce、Tez、Spark 三种引擎(可在会话级别切换)

3. Hive 数据模型

Hive 的数据模型层次从大到小为:Database → Table → Partition → Bucket

3.1 Database(数据库)

类似于关系型数据库中的 Schema,是表的命名空间。

sql 复制代码
-- 创建数据库(在 HDFS 中对应一个目录 /user/hive/warehouse/<db_name>.db/)
CREATE DATABASE IF NOT EXISTS sales_db
  COMMENT 'Sales data warehouse'
  LOCATION '/data/hive/sales'
  WITH DBPROPERTIES ('creator'='admin', 'date'='2024-01-01');

3.2 Table(表)

Hive 中有两种核心表类型:

内部表(Managed Table)
复制代码
默认表类型,Hive 完全管理数据的生命周期。
DROP TABLE 时,HDFS 上的数据文件也会被删除。

数据存储在 hive.metastore.warehouse.dir 配置的目录下(默认 /user/hive/warehouse/<db>/<table>/)。

外部表(External Table)
复制代码
Hive 只管理元数据,不管理实际数据。
DROP TABLE 时,只删除元数据,HDFS 上的数据文件不受影响。
适合数据在 HDFS/S3 上已经存在、由其他工具管理的场景。

3.3 Partition(分区)

将表数据按某一列(分区键)的值划分到不同的 HDFS 子目录中,查询时通过分区裁剪跳过不相关数据:

复制代码
/user/hive/warehouse/orders/
    dt=2024-01-01/   ← 分区目录
    dt=2024-01-02/
    dt=2024-01-03/

分区列不存储在数据文件中,而是体现在目录结构里。

3.4 Bucket(桶/分桶)

在分区(或表)的基础上,进一步将数据按某列的哈希值分散到固定数量的文件(桶)中:

复制代码
/user/hive/warehouse/orders/dt=2024-01-01/
    000000_0   ← 桶 0
    000001_0   ← 桶 1
    000002_0   ← 桶 2
    000003_0   ← 桶 3

分桶的好处:

  • 高效 Bucket JOIN:两张表按相同列以相同桶数分桶,Join 时无需全表扫描
  • 高效 TABLESAMPLE:按桶抽样,效率远高于 RAND() 抽样
  • 数据均匀分布:避免数据倾斜

4. 安装与环境配置

4.1 前置条件

依赖 版本要求
操作系统 Linux(Ubuntu 20.04+ / CentOS 7+)
Java JDK 8(Hive 3.x)或 JDK 11/17/21(Hive 4.x)
Hadoop 已安装运行的 Hadoop 集群(HDFS + YARN)
数据库 Derby(测试)/ MySQL 5.7+(生产)/ PostgreSQL 12+(生产)
内存 推荐 ≥ 8GB RAM

4.2 二进制包安装(传统方式)

步骤一:下载并解压 Hive
bash 复制代码
# 从 https://hive.apache.org/downloads.html 获取最新版本
# 以 Hive 3.1.3 为例
wget https://downloads.apache.org/hive/hive-3.1.3/apache-hive-3.1.3-bin.tar.gz
tar -xzf apache-hive-3.1.3-bin.tar.gz
sudo mv apache-hive-3.1.3-bin /usr/local/hive
步骤二:配置环境变量

编辑 ~/.bashrc/etc/profile,追加:

bash 复制代码
export HIVE_HOME=/usr/local/hive
export PATH=$PATH:$HIVE_HOME/bin
export HIVE_CONF_DIR=$HIVE_HOME/conf
bash 复制代码
source ~/.bashrc
hive --version   # 验证安装
步骤三:创建 HDFS 仓库目录
bash 复制代码
hdfs dfs -mkdir -p /user/hive/warehouse
hdfs dfs -mkdir -p /tmp/hive
hdfs dfs -chmod 777 /user/hive/warehouse
hdfs dfs -chmod 777 /tmp/hive
步骤四:配置 hive-site.xml
bash 复制代码
cp $HIVE_HOME/conf/hive-default.xml.template $HIVE_HOME/conf/hive-site.xml
vim $HIVE_HOME/conf/hive-site.xml

最小化配置(使用嵌入式 Derby,仅用于测试):

xml 复制代码
<configuration>
  <!-- Hive 数据仓库在 HDFS 中的位置 -->
  <property>
    <name>hive.metastore.warehouse.dir</name>
    <value>/user/hive/warehouse</value>
  </property>

  <!-- Hive 临时文件目录 -->
  <property>
    <name>hive.exec.scratchdir</name>
    <value>/tmp/hive</value>
  </property>

  <!-- 执行引擎(mr | tez | spark) -->
  <property>
    <name>hive.execution.engine</name>
    <value>tez</value>
  </property>

  <!-- 启用动态分区 -->
  <property>
    <name>hive.exec.dynamic.partition</name>
    <value>true</value>
  </property>
  <property>
    <name>hive.exec.dynamic.partition.mode</name>
    <value>nonstrict</value>
  </property>
</configuration>
步骤五:初始化 Schema(使用 Derby)
bash 复制代码
# 初始化 Derby 元数据 Schema(只需执行一次)
schematool -dbType derby -initSchema

# 验证
hive
hive> SHOW DATABASES;

4.3 配置 MySQL 作为 Metastore(生产推荐)

步骤一:安装 MySQL 并创建元数据库
bash 复制代码
sudo apt install -y mysql-server
sudo mysql_secure_installation

# 登录 MySQL 创建用户和数据库
mysql -u root -p
sql 复制代码
-- 在 MySQL 中执行
CREATE DATABASE metastore DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE USER 'hive'@'%' IDENTIFIED BY 'hive_password';
GRANT ALL PRIVILEGES ON metastore.* TO 'hive'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT;
步骤二:添加 MySQL JDBC 驱动
bash 复制代码
# 下载 MySQL Connector/J
wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-8.0.33.tar.gz
tar -xzf mysql-connector-java-8.0.33.tar.gz
cp mysql-connector-java-8.0.33/mysql-connector-java-8.0.33.jar $HIVE_HOME/lib/
步骤三:修改 hive-site.xml 指向 MySQL
xml 复制代码
<configuration>
  <!-- Hive 仓库目录 -->
  <property>
    <name>hive.metastore.warehouse.dir</name>
    <value>/user/hive/warehouse</value>
  </property>

  <!-- MySQL 连接信息 -->
  <property>
    <name>javax.jdo.option.ConnectionURL</name>
    <value>jdbc:mysql://localhost:3306/metastore?createDatabaseIfNotExist=true&amp;useSSL=false&amp;serverTimezone=UTC</value>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionDriverName</name>
    <value>com.mysql.cj.jdbc.Driver</value>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionUserName</name>
    <value>hive</value>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionPassword</name>
    <value>hive_password</value>
  </property>

  <!-- Metastore 服务地址(远程模式) -->
  <property>
    <name>hive.metastore.uris</name>
    <value>thrift://localhost:9083</value>
  </property>

  <!-- HiveServer2 配置 -->
  <property>
    <name>hive.server2.thrift.port</name>
    <value>10000</value>
  </property>
  <property>
    <name>hive.server2.thrift.bind.host</name>
    <value>0.0.0.0</value>
  </property>

  <!-- 关闭 doAs(单用户测试时) -->
  <property>
    <name>hive.server2.enable.doAs</name>
    <value>false</value>
  </property>

  <!-- 动态分区配置 -->
  <property>
    <name>hive.exec.dynamic.partition</name>
    <value>true</value>
  </property>
  <property>
    <name>hive.exec.dynamic.partition.mode</name>
    <value>nonstrict</value>
  </property>
</configuration>
步骤四:初始化 MySQL Metastore Schema
bash 复制代码
schematool -dbType mysql -initSchema

# 验证 schema 版本
schematool -dbType mysql -info

4.4 启动 Hive 服务

bash 复制代码
# 1. 确保 Hadoop 已启动
jps | grep -E "NameNode|DataNode|ResourceManager|NodeManager"

# 2. 启动 Metastore 服务(后台运行)
hive --service metastore &
# 或
nohup hive --service metastore > /tmp/metastore.log 2>&1 &

# 验证 Metastore 是否在 9083 端口监听
netstat -tuln | grep 9083

# 3. 启动 HiveServer2(后台运行)
hive --service hiveserver2 &
# 或
nohup hive --service hiveserver2 > /tmp/hiveserver2.log 2>&1 &

# 验证 HiveServer2 是否在 10000 端口监听
netstat -tuln | grep 10000

# 4. 访问 HiveServer2 Web UI
# http://localhost:10002

4.5 Docker 快速启动(入门推荐)

这是最快速的入门方式,官方提供完整 Docker 镜像:

bash 复制代码
export HIVE_VERSION=4.0.1

# 方式一:最简单,使用嵌入式 Derby,数据不持久化(快速体验)
docker run -d -p 10000:10000 -p 10002:10002 \
  --env SERVICE_NAME=hiveserver2 \
  --name hive4 \
  apache/hive:${HIVE_VERSION}

# 连接到 Beeline
docker exec -it hive4 beeline -u 'jdbc:hive2://localhost:10000/'
bash 复制代码
# 方式二:使用 docker-compose,HiveServer2 + Metastore + PostgreSQL(数据持久化)
# 创建 compose.yaml 文件
cat > compose.yaml << 'EOF'
version: "3"
services:
  postgres:
    image: postgres:17.2
    environment:
      POSTGRES_PASSWORD: "hivepassword"
      POSTGRES_DB: "metastore"
    volumes:
      - postgres-data:/var/lib/postgresql/data

  metastore:
    image: apache/hive:4.0.1
    depends_on:
      - postgres
    environment:
      SERVICE_NAME: metastore
      DB_DRIVER: postgres
      SERVICE_OPTS: >-
        -Djavax.jdo.option.ConnectionDriverName=org.postgresql.Driver
        -Djavax.jdo.option.ConnectionURL=jdbc:postgresql://postgres:5432/metastore
        -Djavax.jdo.option.ConnectionUserName=postgres
        -Djavax.jdo.option.ConnectionPassword=hivepassword
    ports:
      - "9083:9083"

  hiveserver2:
    image: apache/hive:4.0.1
    depends_on:
      - metastore
    environment:
      SERVICE_NAME: hiveserver2
      IS_RESUME: "true"
      SERVICE_OPTS: "-Dhive.metastore.uris=thrift://metastore:9083"
    ports:
      - "10000:10000"
      - "10002:10002"
    volumes:
      - warehouse:/opt/hive/data/warehouse

volumes:
  postgres-data:
  warehouse:
EOF

docker-compose up -d

# 连接 Beeline
docker exec -it hiveserver2-container beeline -u 'jdbc:hive2://localhost:10000/'

5. HiveQL DDL 数据定义语言

5.1 数据库操作

sql 复制代码
-- 创建数据库
CREATE DATABASE IF NOT EXISTS mydb
  COMMENT '我的数据仓库'
  LOCATION '/data/hive/mydb'
  WITH DBPROPERTIES ('owner'='dataeng', 'version'='1.0');

-- 查看数据库列表
SHOW DATABASES;
SHOW DATABASES LIKE 'my*';    -- 支持通配符

-- 查看数据库详情
DESCRIBE DATABASE EXTENDED mydb;

-- 切换数据库
USE mydb;

-- 删除数据库(CASCADE 同时删除表)
DROP DATABASE IF EXISTS mydb CASCADE;

-- 修改数据库属性
ALTER DATABASE mydb SET DBPROPERTIES ('updated_by'='admin');

5.2 表的创建(内部表 vs 外部表)

完整的 CREATE TABLE 语法
sql 复制代码
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
(
  col_name  data_type  [COMMENT 'column comment'],
  ...
)
[COMMENT 'table comment']
[PARTITIONED BY (col_name data_type [COMMENT ...], ...)]
[CLUSTERED BY (col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION 'hdfs_path']
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement]
内部表示例
sql 复制代码
-- 基本内部表
CREATE TABLE IF NOT EXISTS employees (
  emp_id      INT           COMMENT '员工ID',
  name        STRING        COMMENT '姓名',
  dept        STRING        COMMENT '部门',
  salary      DOUBLE        COMMENT '薪资',
  hire_date   DATE          COMMENT '入职日期',
  skills      ARRAY<STRING> COMMENT '技能列表',
  address     STRUCT<city:STRING, zip:STRING> COMMENT '地址'
)
COMMENT '员工信息表'
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY '\t'
  COLLECTION ITEMS TERMINATED BY ','
  MAP KEYS TERMINATED BY ':'
  LINES TERMINATED BY '\n'
STORED AS TEXTFILE
TBLPROPERTIES ('author'='admin', 'create_time'='2024-01-01');

-- 使用 ORC 格式(推荐生产使用)
CREATE TABLE orders_orc (
  order_id    BIGINT,
  user_id     INT,
  amount      DECIMAL(10,2),
  create_time TIMESTAMP
)
STORED AS ORC
TBLPROPERTIES ('orc.compress'='SNAPPY');

-- 使用 CTAS(Create Table As Select)从已有表创建
CREATE TABLE dept_summary
STORED AS ORC
AS
SELECT dept, COUNT(*) AS cnt, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept;
外部表示例
sql 复制代码
-- 创建外部表,指向 HDFS 上已有数据
CREATE EXTERNAL TABLE web_logs (
  ip          STRING,
  log_time    STRING,
  request     STRING,
  status      INT,
  bytes       BIGINT
)
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY ' '
STORED AS TEXTFILE
LOCATION '/data/weblogs/2024/'
TBLPROPERTIES ('skip.header.line.count'='1');  -- 跳过 CSV 头行

-- 外部表(Parquet 格式,指向 S3)
CREATE EXTERNAL TABLE s3_events (
  event_id    STRING,
  event_type  STRING,
  user_id     BIGINT,
  event_time  TIMESTAMP
)
STORED AS PARQUET
LOCATION 's3a://my-bucket/events/';
查看表信息
sql 复制代码
SHOW TABLES;                          -- 列出所有表
SHOW TABLES LIKE 'order*';            -- 模糊查找
DESCRIBE employees;                   -- 查看表结构(列名、类型)
DESCRIBE FORMATTED employees;         -- 查看详细信息(包括 HDFS 路径、格式等)
DESCRIBE EXTENDED employees;          -- 查看更详细信息(包括原始元数据)
SHOW CREATE TABLE employees;          -- 查看建表语句
SHOW TBLPROPERTIES employees;         -- 查看表属性

5.3 分区表

sql 复制代码
-- 创建分区表(按日期分区)
CREATE TABLE user_events (
  user_id     BIGINT,
  event_type  STRING,
  event_time  TIMESTAMP,
  page_url    STRING
)
PARTITIONED BY (
  dt          STRING   COMMENT '日期分区,格式 yyyy-MM-dd',
  country     STRING   COMMENT '国家分区'
)
STORED AS ORC;

-- 手动添加分区(静态分区)
ALTER TABLE user_events ADD PARTITION (dt='2024-01-01', country='CN')
  LOCATION '/data/events/dt=2024-01-01/country=CN';

-- 添加多个分区
ALTER TABLE user_events ADD
  PARTITION (dt='2024-01-02', country='CN')
  PARTITION (dt='2024-01-02', country='US');

-- 删除分区(同时删除数据,如果是内部表)
ALTER TABLE user_events DROP PARTITION (dt='2023-12-01');
ALTER TABLE user_events DROP PARTITION (dt < '2023-01-01');  -- 按条件批量删除

-- 查看分区列表
SHOW PARTITIONS user_events;
SHOW PARTITIONS user_events PARTITION (dt='2024-01-01');

-- 修复分区(当 HDFS 目录已存在但 Metastore 没有记录时)
MSCK REPAIR TABLE user_events;

-- 查询时分区裁剪(必须加分区条件,否则全表扫描)
SELECT COUNT(*) FROM user_events WHERE dt='2024-01-01' AND country='CN';

5.4 分桶表

sql 复制代码
-- 创建分桶表(按 user_id 哈希分为 32 个桶)
CREATE TABLE user_orders (
  order_id  BIGINT,
  user_id   INT,
  amount    DOUBLE,
  status    STRING
)
CLUSTERED BY (user_id) SORTED BY (order_id ASC) INTO 32 BUCKETS
STORED AS ORC;

-- 同时使用分区和分桶
CREATE TABLE user_behavior (
  user_id   BIGINT,
  action    STRING,
  item_id   BIGINT
)
PARTITIONED BY (dt STRING)
CLUSTERED BY (user_id) INTO 256 BUCKETS
STORED AS ORC;

-- 向分桶表插入数据(必须启用 bucketing 支持)
SET hive.enforce.bucketing = true;  -- Hive 1.x 需要,2.x+ 已默认
INSERT INTO user_orders SELECT order_id, user_id, amount, status FROM raw_orders;

-- 分桶采样查询
SELECT * FROM user_orders TABLESAMPLE(BUCKET 1 OUT OF 32 ON user_id);   -- 取第1个桶
SELECT * FROM user_orders TABLESAMPLE(BUCKET 1 OUT OF 8 ON user_id);    -- 取前4个桶(32/8=4)

5.5 表结构修改

sql 复制代码
-- 重命名表
ALTER TABLE employees RENAME TO staff;

-- 添加列
ALTER TABLE employees ADD COLUMNS (
  phone  STRING COMMENT '手机号',
  email  STRING COMMENT '邮箱'
);

-- 修改列(改名/改类型)
ALTER TABLE employees CHANGE COLUMN name full_name STRING COMMENT '全名';

-- 替换所有列(重新定义列结构)
ALTER TABLE employees REPLACE COLUMNS (
  emp_id INT,
  full_name STRING,
  salary DOUBLE
);

-- 修改表属性
ALTER TABLE employees SET TBLPROPERTIES ('last_modified_by'='admin');

-- 修改存储格式
ALTER TABLE employees SET FILEFORMAT ORC;

-- 修改表位置
ALTER TABLE employees SET LOCATION '/new/hdfs/path/';

-- 分区表修改分区属性
ALTER TABLE user_events PARTITION (dt='2024-01-01') SET FILEFORMAT ORC;

-- 合并小文件(ORC 格式支持)
ALTER TABLE user_events PARTITION (dt='2024-01-01') CONCATENATE;

5.6 视图(View)

sql 复制代码
-- 创建视图
CREATE VIEW IF NOT EXISTS active_employees AS
SELECT emp_id, name, dept, salary
FROM employees
WHERE hire_date > '2020-01-01' AND salary > 5000;

-- 查询视图(和查询普通表一样)
SELECT dept, COUNT(*) FROM active_employees GROUP BY dept;

-- 修改视图
ALTER VIEW active_employees AS
SELECT emp_id, name, dept, salary, hire_date
FROM employees
WHERE salary > 8000;

-- 删除视图
DROP VIEW IF EXISTS active_employees;

-- 物化视图(Hive 3.0+,需要 ACID)
CREATE MATERIALIZED VIEW emp_dept_summary
AS SELECT dept, COUNT(*) cnt, AVG(salary) avg_sal
FROM employees GROUP BY dept;

-- 重建物化视图(更新缓存)
ALTER MATERIALIZED VIEW emp_dept_summary REBUILD;

6. HiveQL DML 数据操作语言

6.1 数据加载(LOAD DATA)

sql 复制代码
-- 从本地文件系统加载(LOCAL 关键字表示本地文件)
-- 注意:会将文件移动/复制到 HDFS 仓库目录
LOAD DATA LOCAL INPATH '/home/user/data/employees.csv'
  INTO TABLE employees;

-- 加载并覆盖现有数据
LOAD DATA LOCAL INPATH '/home/user/data/employees.csv'
  OVERWRITE INTO TABLE employees;

-- 从 HDFS 加载(不加 LOCAL,文件从 HDFS 移动到表目录)
LOAD DATA INPATH '/data/raw/employees.csv'
  INTO TABLE employees;

-- 加载数据到特定分区
LOAD DATA LOCAL INPATH '/data/events_20240101.csv'
  INTO TABLE user_events PARTITION (dt='2024-01-01', country='CN');

注意:LOAD DATA 是纯文件移动操作,不进行 MapReduce,速度很快。它不会验证数据格式和类型。

6.2 INSERT 语句

sql 复制代码
-- INSERT INTO(追加数据)
INSERT INTO TABLE employees VALUES
  (1001, 'Alice', 'Engineering', 12000.00, '2022-03-15'),
  (1002, 'Bob', 'Marketing', 9500.00, '2021-07-01');

-- INSERT OVERWRITE(覆盖数据)
INSERT OVERWRITE TABLE dept_summary
SELECT dept, COUNT(*) cnt, AVG(salary) avg_sal
FROM employees GROUP BY dept;

-- 动态分区插入(自动根据查询结果创建分区)
SET hive.exec.dynamic.partition.mode = nonstrict;
INSERT OVERWRITE TABLE user_events PARTITION (dt, country)
SELECT user_id, event_type, event_time, page_url, dt, country
FROM raw_events
WHERE dt >= '2024-01-01';

-- 多目标插入(一次扫描,写多张表,性能优化技巧)
FROM employees
INSERT OVERWRITE TABLE high_salary_emp
  SELECT * WHERE salary > 15000
INSERT INTO TABLE mid_salary_emp
  SELECT * WHERE salary BETWEEN 8000 AND 15000
INSERT INTO TABLE low_salary_emp
  SELECT * WHERE salary < 8000;

-- INSERT INTO ... SELECT(从查询结果插入)
INSERT INTO TABLE orders_backup
SELECT * FROM orders WHERE YEAR(create_time) = 2023;

6.3 SELECT 查询详解

sql 复制代码
-- 基本查询
SELECT emp_id, name, salary
FROM employees
WHERE dept = 'Engineering' AND salary > 10000
ORDER BY salary DESC
LIMIT 10;

-- 聚合查询
SELECT dept,
       COUNT(*)          AS employee_count,
       AVG(salary)       AS avg_salary,
       MAX(salary)       AS max_salary,
       MIN(salary)       AS min_salary,
       SUM(salary)       AS total_salary
FROM employees
GROUP BY dept
HAVING COUNT(*) > 5
ORDER BY avg_salary DESC;

-- DISTINCT
SELECT DISTINCT dept FROM employees;
SELECT COUNT(DISTINCT dept) FROM employees;  -- 统计唯一部门数

-- 正则表达式查询(REGEXP / RLIKE)
SELECT name FROM employees WHERE name RLIKE '^A.*';
SELECT name FROM employees WHERE name REGEXP 'Alice|Bob';

-- LIKE 模糊查询
SELECT name FROM employees WHERE name LIKE 'A%';
SELECT name FROM employees WHERE name LIKE '_ob';  -- 下划线匹配单个字符

-- BETWEEN ... AND
SELECT * FROM employees WHERE salary BETWEEN 8000 AND 12000;

-- IN 子句
SELECT * FROM employees WHERE dept IN ('Engineering', 'Marketing', 'Finance');

-- IS NULL / IS NOT NULL
SELECT * FROM employees WHERE email IS NULL;

-- CASE WHEN
SELECT name,
       salary,
       CASE
         WHEN salary >= 15000 THEN '高薪'
         WHEN salary >= 10000 THEN '中薪'
         ELSE '低薪'
       END AS salary_level
FROM employees;

-- SORT BY vs ORDER BY vs DISTRIBUTE BY vs CLUSTER BY
-- ORDER BY: 全局排序(只有一个 Reducer),大数据量慎用
SELECT * FROM employees ORDER BY salary DESC;

-- SORT BY: 每个 Reducer 内部排序(局部有序)
SELECT * FROM employees SORT BY salary DESC;

-- DISTRIBUTE BY: 按指定列分发到 Reducer(常与 SORT BY 配合)
SELECT * FROM employees DISTRIBUTE BY dept SORT BY dept, salary DESC;

-- CLUSTER BY: 等价于 DISTRIBUTE BY col SORT BY col(相同列升序)
SELECT * FROM employees CLUSTER BY dept;

-- LIMIT 与 OFFSET
SELECT * FROM employees ORDER BY salary DESC LIMIT 10;
SELECT * FROM employees ORDER BY salary DESC LIMIT 10 OFFSET 20;  -- 第 21-30 条

-- TABLESAMPLE 数据采样
SELECT * FROM employees TABLESAMPLE(10 PERCENT);          -- 随机采样 10%
SELECT * FROM employees TABLESAMPLE(1000 ROWS);           -- 采样 1000 行
SELECT * FROM user_orders TABLESAMPLE(BUCKET 2 OUT OF 32 ON user_id);  -- 桶采样

-- LATERAL VIEW EXPLODE(展开数组/Map 列)
SELECT emp_id, name, skill
FROM employees
LATERAL VIEW EXPLODE(skills) tmp AS skill;

-- LATERAL VIEW json_tuple(解析 JSON)
SELECT base.id, jt.name, jt.age
FROM json_table base
LATERAL VIEW json_tuple(base.json_col, 'name', 'age') jt AS name, age;

6.4 JOIN 操作

sql 复制代码
-- INNER JOIN
SELECT e.name, e.salary, d.dept_name, d.location
FROM employees e
INNER JOIN departments d ON e.dept = d.dept_id;

-- LEFT OUTER JOIN
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept = d.dept_id;

-- RIGHT OUTER JOIN
SELECT e.name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.dept = d.dept_id;

-- FULL OUTER JOIN
SELECT e.name, d.dept_name
FROM employees e
FULL OUTER JOIN departments d ON e.dept = d.dept_id;

-- CROSS JOIN(笛卡尔积,谨慎使用!)
SELECT e.name, d.dept_name
FROM employees e CROSS JOIN departments d;

-- LEFT SEMI JOIN(相当于 EXISTS,效率高于子查询)
SELECT e.*
FROM employees e
LEFT SEMI JOIN high_salary_list h ON e.emp_id = h.emp_id;

-- MAP JOIN(小表 JOIN,广播到所有 Map 端,避免 Reduce)
-- 自动触发条件:hive.auto.convert.join=true 且小表 < hive.mapjoin.smalltable.filesize
SELECT /*+ MAPJOIN(d) */
       e.name, d.dept_name
FROM employees e
JOIN departments d ON e.dept = d.dept_id;

-- Bucket Map Join(两张表均按相同列分桶时效率最高)
-- 需要设置:set hive.optimize.bucketmapjoin=true

6.5 子查询与 CTE

sql 复制代码
-- 子查询(IN)
SELECT * FROM employees
WHERE dept IN (
  SELECT dept_id FROM departments WHERE location = 'Beijing'
);

-- 子查询(EXISTS)
SELECT * FROM employees e
WHERE EXISTS (
  SELECT 1 FROM high_performers h WHERE h.emp_id = e.emp_id
);

-- FROM 子句中的子查询
SELECT dept, avg_sal
FROM (
  SELECT dept, AVG(salary) AS avg_sal
  FROM employees
  GROUP BY dept
) t
WHERE avg_sal > 10000;

-- CTE(Common Table Expression,WITH 子句)------ Hive 0.13+
WITH
dept_stats AS (
  SELECT dept, COUNT(*) cnt, AVG(salary) avg_sal
  FROM employees
  GROUP BY dept
),
high_dept AS (
  SELECT dept FROM dept_stats WHERE avg_sal > 10000
)
SELECT e.name, e.salary, e.dept
FROM employees e
JOIN high_dept h ON e.dept = h.dept;

6.6 窗口函数(Window Functions)

窗口函数是 Hive 中非常强大的分析工具:

sql 复制代码
-- 语法:function() OVER ([PARTITION BY ...] [ORDER BY ...] [frame_clause])

-- ROW_NUMBER:每行一个唯一序号
SELECT name, dept, salary,
       ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn
FROM employees;

-- RANK:允许并列,跳号(1,1,3)
SELECT name, dept, salary,
       RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rnk
FROM employees;

-- DENSE_RANK:允许并列,不跳号(1,1,2)
SELECT name, dept, salary,
       DENSE_RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS dense_rnk
FROM employees;

-- 取每个部门工资前3名(ROW_NUMBER 去重)
SELECT * FROM (
  SELECT name, dept, salary,
         ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn
  FROM employees
) t WHERE rn <= 3;

-- LAG / LEAD:访问前/后 N 行数据
SELECT name, salary,
       LAG(salary, 1, 0)  OVER (PARTITION BY dept ORDER BY hire_date) AS prev_salary,
       LEAD(salary, 1, 0) OVER (PARTITION BY dept ORDER BY hire_date) AS next_salary
FROM employees;

-- FIRST_VALUE / LAST_VALUE
SELECT name, dept, salary,
       FIRST_VALUE(name) OVER (PARTITION BY dept ORDER BY salary DESC) AS top_earner
FROM employees;

-- SUM/AVG/COUNT 累计汇总
SELECT name, dept, salary,
       SUM(salary)   OVER (PARTITION BY dept ORDER BY hire_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total,
       AVG(salary)   OVER (PARTITION BY dept)                                                                   AS dept_avg,
       COUNT(*)      OVER ()                                                                                    AS total_employees
FROM employees;

-- NTILE:将数据分成 N 等份
SELECT name, salary,
       NTILE(4) OVER (ORDER BY salary) AS quartile
FROM employees;

-- PERCENT_RANK / CUME_DIST
SELECT name, salary,
       PERCENT_RANK() OVER (ORDER BY salary) AS pct_rank,
       CUME_DIST()    OVER (ORDER BY salary) AS cume_dist
FROM employees;

-- 帧规范(Frame Specification)
-- ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW  → 从头到当前行
-- ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING          → 前2行到后2行(滑动窗口)
-- RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING → 当前行到末尾
SELECT name, salary,
       AVG(salary) OVER (
         PARTITION BY dept
         ORDER BY hire_date
         ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING
       ) AS moving_avg
FROM employees;

6.7 ACID 事务(UPDATE / DELETE)

Hive 0.14+ 支持行级别的 UPDATE/DELETE,但需要满足以下条件:

sql 复制代码
-- 前置配置(hive-site.xml 或 SET 命令)
SET hive.support.concurrency = true;
SET hive.enforce.bucketing = true;
SET hive.exec.dynamic.partition.mode = nonstrict;
SET hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
SET hive.compactor.initiator.on = true;
SET hive.compactor.worker.threads = 1;

-- 建表必须使用 ORC 格式 + TRANSACTIONAL 属性
CREATE TABLE student (
  id    INT,
  name  STRING,
  score INT
)
CLUSTERED BY (id) INTO 4 BUCKETS
STORED AS ORC
TBLPROPERTIES ('transactional'='true');

-- UPDATE 语句
UPDATE student SET score = 95 WHERE id = 1001;
UPDATE student SET name = 'Alice Zhang', score = score + 5 WHERE name = 'Alice';

-- DELETE 语句
DELETE FROM student WHERE id = 1005;
DELETE FROM student WHERE score < 60;

-- MERGE(Hive 2.2+,Upsert 操作)
MERGE INTO student AS target
USING updates AS source
ON target.id = source.id
WHEN MATCHED AND source.action = 'UPDATE' THEN
  UPDATE SET name = source.name, score = source.score
WHEN MATCHED AND source.action = 'DELETE' THEN DELETE
WHEN NOT MATCHED THEN
  INSERT VALUES (source.id, source.name, source.score);

7. Hive 数据类型详解

7.1 基本数据类型

类型 字节 范围/说明 示例
TINYINT 1B -128 ~ 127 100Y
SMALLINT 2B -32768 ~ 32767 1000S
INT / INTEGER 4B -2^31 ~ 2^31-1 100
BIGINT 8B -2^63 ~ 2^63-1 100L
FLOAT 4B 单精度浮点数 3.14
DOUBLE 8B 双精度浮点数 3.14159265
DECIMAL(p,s) 可变 精确小数,p 总精度,s 小数位 DECIMAL(10,2)
BOOLEAN - TRUE / FALSE true
STRING 可变 无长度限制的字符串(UTF-8) 'hello'
VARCHAR(n) 可变 最大长度 n 的字符串 VARCHAR(255)
CHAR(n) 固定 固定长度字符串,不足补空格 CHAR(10)
BINARY 可变 字节数组 -
TIMESTAMP - 纳秒精度时间戳 '2024-01-01 12:00:00'
DATE - 仅日期(无时间) '2024-01-01'
INTERVAL - 时间间隔 INTERVAL '1' DAY

7.2 复杂数据类型

类型 语法 说明 示例
ARRAY ARRAY<data_type> 有序列表,下标从 0 开始 ['a','b','c']
MAP MAP<key_type, val_type> 键值对,key 必须是基本类型 {'k1':1,'k2':2}
STRUCT STRUCT<name:type,...> 命名字段的结构体 {'name':'Alice','age':30}
UNIONTYPE UNIONTYPE<t1,t2,...> 联合类型(较少使用) -
sql 复制代码
-- 复杂类型的使用示例
CREATE TABLE complex_example (
  id      INT,
  tags    ARRAY<STRING>,             -- 数组
  props   MAP<STRING, STRING>,       -- Map
  address STRUCT<city:STRING, zip:STRING, country:STRING>  -- 结构体
);

-- 插入复杂类型数据
INSERT INTO complex_example VALUES (
  1,
  ARRAY('hive', 'hadoop', 'spark'),
  MAP('color', 'blue', 'size', 'L'),
  NAMED_STRUCT('city', 'Beijing', 'zip', '100000', 'country', 'CN')
);

-- 访问复杂类型
SELECT
  id,
  tags[0]              AS first_tag,    -- 数组下标访问
  tags[1]              AS second_tag,
  SIZE(tags)           AS tag_count,    -- 数组大小
  props['color']       AS color,        -- Map 键访问
  address.city         AS city,         -- Struct 字段访问
  address.zip          AS zip
FROM complex_example;

-- EXPLODE 展开数组
SELECT id, tag
FROM complex_example
LATERAL VIEW EXPLODE(tags) tmp AS tag;

-- EXPLODE 展开 Map
SELECT id, k, v
FROM complex_example
LATERAL VIEW EXPLODE(props) tmp AS k, v;

7.3 类型转换

sql 复制代码
-- 隐式转换(自动类型提升:TINYINT → SMALLINT → INT → BIGINT → FLOAT → DOUBLE)
SELECT 1 + 1.5;   -- 自动转为 DOUBLE

-- 显式转换(CAST)
SELECT CAST('123' AS INT);
SELECT CAST(3.14 AS INT);                  -- 截断 → 3
SELECT CAST('2024-01-01' AS DATE);
SELECT CAST(salary AS STRING) FROM employees;

-- 字符串与数字转换
SELECT CAST('123abc' AS INT);  -- 返回 NULL(无法转换)

-- 日期类型转换
SELECT TO_DATE('2024-01-15 12:30:00');    -- → '2024-01-15'
SELECT UNIX_TIMESTAMP('2024-01-01 00:00:00', 'yyyy-MM-dd HH:mm:ss');  -- → 秒级时间戳
SELECT FROM_UNIXTIME(1704067200, 'yyyy-MM-dd HH:mm:ss');  -- 时间戳 → 字符串

8. Hive 文件格式与存储

8.1 支持的文件格式对比

格式 存储方式 压缩支持 查询性能 写入性能 适用场景
TextFile 行式,纯文本 gzip/bzip2 等 数据交换、调试、原始日志
SequenceFile 行式,二进制 Block/Record 一般 一般 Hadoop 原生,历史遗留
RCFile 列式,行组 支持 中等 一般 旧系统
ORC 列式(带索引) Zlib/Snappy/LZ4 极好 中等 生产推荐:分析型查询
Parquet 列式 Gzip/Snappy/LZ4 极好 中等 生产推荐:与 Spark 互通
Avro 行式,带 Schema Deflate/Snappy 中等 数据序列化、Kafka 数据落地

8.2 ORC 格式详解(推荐)

ORC(Optimized Row Columnar)是 Hive 原生的高性能列式文件格式:

ORC 文件结构:

复制代码
ORC 文件
├── Stripe 1(默认 64MB)
│   ├── Index Data(轻量级索引,每 10000 行一个)
│   ├── Row Data(实际列数据)
│   └── Stripe Footer(列统计信息)
├── Stripe 2
│   └── ...
└── File Footer
    ├── 文件级统计信息(行数、列最大/最小值等)
    └── Stripe 位置信息

ORC 的核心优化:

  • 列投影(Column Projection):只读取查询涉及的列
  • 谓词下推(Predicate Pushdown):利用 Stripe/Row Group 统计信息跳过无关数据
  • Bloom Filter 索引:快速判断某个 Stripe 是否包含目标值
  • Run-Length Encoding(RLE):对整数列压缩效果极好
  • Dictionary Encoding:对低基数字符串列压缩率极高
sql 复制代码
-- 使用 ORC 格式建表
CREATE TABLE sales (
  sale_id   BIGINT,
  product   STRING,
  amount    DECIMAL(12,2),
  sale_date DATE
)
STORED AS ORC
TBLPROPERTIES (
  'orc.compress'='SNAPPY',         -- 压缩算法:NONE/ZLIB/SNAPPY/LZ4(推荐 SNAPPY)
  'orc.stripe.size'='67108864',    -- Stripe 大小 64MB
  'orc.row.index.stride'='10000',  -- 行组索引步长
  'orc.create.index'='true'        -- 启用行组索引
);

-- 将 TextFile 表转换为 ORC
CREATE TABLE sales_orc STORED AS ORC AS SELECT * FROM sales_text;

8.3 Parquet 格式详解

Parquet 是跨语言的通用列式格式,与 Spark、Impala、Presto 互通性最好:

sql 复制代码
-- 使用 Parquet 建表
CREATE TABLE events_parquet (
  event_id   STRING,
  user_id    BIGINT,
  event_type STRING,
  ts         TIMESTAMP
)
STORED AS PARQUET
TBLPROPERTIES (
  'parquet.compression'='SNAPPY'  -- UNCOMPRESSED/GZIP/SNAPPY/LZO/BROTLI/LZ4
);

8.4 压缩配置

sql 复制代码
-- 开启中间结果(Map 输出)压缩
SET hive.exec.compress.intermediate=true;
SET mapreduce.map.output.compress=true;
SET mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;

-- 开启最终输出压缩
SET hive.exec.compress.output=true;
SET mapreduce.output.fileoutputformat.compress=true;
SET mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
SET mapreduce.output.fileoutputformat.compress.type=BLOCK;

-- Tez 引擎中间数据压缩
SET tez.runtime.compress=true;
SET tez.runtime.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;

9. SerDe(Serialization / Deserialization)

SerDe 是 Hive 读写文件的核心接口,决定了 Hive 如何解析和序列化数据。

9.1 常用内置 SerDe

LazySimpleSerDe(默认)
sql 复制代码
-- 解析分隔符文本
CREATE TABLE csv_data (
  id   INT,
  name STRING,
  age  INT
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
  'field.delim'=',',
  'line.delim'='\n',
  'null.format'='\\N'
)
STORED AS TEXTFILE;

-- 简写方式(等价于上面)
CREATE TABLE csv_data2 (id INT, name STRING, age INT)
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY ','
  LINES TERMINATED BY '\n'
  NULL DEFINED AS '\\N'
STORED AS TEXTFILE;
JsonSerDe
sql 复制代码
-- 解析 JSON 格式文件(每行一个 JSON)
CREATE TABLE json_logs (
  user_id   INT,
  action    STRING,
  timestamp BIGINT,
  metadata  MAP<STRING, STRING>
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS TEXTFILE;
RegexSerDe(正则表达式)
sql 复制代码
-- 用正则表达式解析复杂格式(如 Apache 日志)
CREATE TABLE apache_logs (
  ip        STRING,
  identity  STRING,
  user      STRING,
  time      STRING,
  request   STRING,
  status    INT,
  size      INT
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
  'input.regex' = '([^ ]*) ([^ ]*) ([^ ]*) \\[([^\\]]*)\\] "([^"]*)" ([0-9]*) ([0-9]*)'
)
STORED AS TEXTFILE;
OpenCSVSerde
sql 复制代码
-- 处理包含转义字符的复杂 CSV
CREATE TABLE complex_csv (
  id    STRING,
  name  STRING,
  desc  STRING
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
  'separatorChar'=',',
  'quoteChar'='"',
  'escapeChar'='\\'
)
STORED AS TEXTFILE;

10. Hive 内置函数大全

10.1 字符串函数

sql 复制代码
-- 基本操作
SELECT LENGTH('hello world');              -- 11
SELECT LOWER('Hello WORLD');              -- hello world
SELECT UPPER('hello world');              -- HELLO WORLD
SELECT TRIM('  hello  ');                 -- hello
SELECT LTRIM('  hello  ');                -- 'hello  '
SELECT RTRIM('  hello  ');                -- '  hello'

-- 截取与拼接
SELECT SUBSTR('hello world', 1, 5);       -- hello(下标从 1 开始)
SELECT SUBSTRING('hello world', 7);       -- world
SELECT CONCAT('hello', ' ', 'world');     -- hello world
SELECT CONCAT_WS('-', 'a', 'b', 'c');     -- a-b-c(带分隔符)

-- 查找与替换
SELECT INSTR('hello world', 'world');     -- 7(位置)
SELECT LOCATE('world', 'hello world');    -- 7
SELECT REPLACE('hello world', 'world', 'hive');  -- hello hive
SELECT REGEXP_REPLACE('abc123def', '[0-9]+', 'NUM');  -- abcNUMdef
SELECT REGEXP_EXTRACT('abc123def', '[0-9]+', 0);      -- 123

-- 分割与拼接
SELECT SPLIT('a,b,c', ',');               -- ["a","b","c"](返回数组)
SELECT SPLIT('a,b,c', ',')[1];            -- b(取第2个)

-- 格式化
SELECT LPAD('5', 4, '0');                 -- 0005(左填充)
SELECT RPAD('5', 4, '0');                 -- 5000(右填充)
SELECT PRINTF('%05d', 42);               -- 00042
SELECT FORMAT_NUMBER(1234567.89, 2);     -- 1,234,567.89

-- 字符串判断
SELECT LIKE('hello', 'hel%');            -- true
SELECT RLIKE('hello123', '[a-z]+[0-9]+'); -- true

-- 其他
SELECT REVERSE('hello');                  -- olleh
SELECT REPEAT('ab', 3);                   -- ababab
SELECT SPACE(5);                          -- '     '(5 个空格)
SELECT ASCII('A');                        -- 65
SELECT CHR(65);                           -- A
SELECT QUOTE('it''s');                    -- 'it\'s'
SELECT INITCAP('hello world');            -- Hello World

10.2 数学函数

sql 复制代码
SELECT ROUND(3.567, 2);              -- 3.57
SELECT FLOOR(3.7);                   -- 3
SELECT CEIL(3.2);                    -- 4
SELECT ABS(-5);                      -- 5
SELECT SQRT(16);                     -- 4.0
SELECT POWER(2, 10);                 -- 1024.0
SELECT LOG(10, 100);                 -- 2.0(log 以 10 为底)
SELECT LN(2.718281);                 -- ≈1.0
SELECT EXP(1);                       -- ≈2.718
SELECT MOD(10, 3);                   -- 1
SELECT SIGN(-5);                     -- -1(正数1,负数-1,零0)
SELECT PI();                         -- 3.141592653589793
SELECT SIN(0), COS(0), TAN(0);      -- 0.0, 1.0, 0.0
SELECT RAND();                       -- 0~1 随机数
SELECT RAND(42);                     -- 固定种子的随机数
SELECT GREATEST(3, 1, 4, 1, 5, 9);  -- 9
SELECT LEAST(3, 1, 4, 1, 5, 9);     -- 1
SELECT FACTORIAL(5);                 -- 120
SELECT SHIFTLEFT(8, 2);              -- 32(位运算左移)
SELECT SHIFTRIGHT(32, 2);            -- 8(位运算右移)
SELECT HEX(255);                     -- FF
SELECT UNHEX('FF');                  -- 255

10.3 日期和时间函数

sql 复制代码
-- 获取当前时间
SELECT CURRENT_DATE();               -- 2024-01-01
SELECT CURRENT_TIMESTAMP();          -- 2024-01-01 12:00:00.000
SELECT NOW();                        -- 等价于 CURRENT_TIMESTAMP()
SELECT UNIX_TIMESTAMP();             -- 当前 Unix 时间戳(秒)

-- 日期解析与格式化
SELECT TO_DATE('2024-01-15 12:30:00');          -- 2024-01-15
SELECT DATE_FORMAT('2024-01-15', 'yyyyMMdd');   -- 20240115
SELECT UNIX_TIMESTAMP('2024-01-01', 'yyyy-MM-dd');    -- → 1704067200
SELECT FROM_UNIXTIME(1704067200);               -- 2024-01-01 00:00:00
SELECT FROM_UNIXTIME(1704067200, 'yyyy-MM-dd'); -- 2024-01-01

-- 日期提取
SELECT YEAR('2024-01-15');           -- 2024
SELECT MONTH('2024-01-15');          -- 1
SELECT DAY('2024-01-15');            -- 15
SELECT HOUR('2024-01-15 12:30:45'); -- 12
SELECT MINUTE('2024-01-15 12:30:45'); -- 30
SELECT SECOND('2024-01-15 12:30:45'); -- 45
SELECT WEEKOFYEAR('2024-01-15');     -- 3(第3周)
SELECT DAYOFWEEK('2024-01-15');      -- 2(1=周日,2=周一...)
SELECT QUARTER('2024-04-15');        -- 2

-- 日期运算
SELECT DATE_ADD('2024-01-15', 10);   -- 2024-01-25
SELECT DATE_SUB('2024-01-15', 10);   -- 2024-01-05
SELECT DATEDIFF('2024-01-15', '2024-01-01');   -- 14(天数差)
SELECT ADD_MONTHS('2024-01-15', 2);  -- 2024-03-15
SELECT LAST_DAY('2024-02-01');       -- 2024-02-29(当月最后一天)
SELECT NEXT_DAY('2024-01-15', 'Monday'); -- 下一个星期一

-- 日期截断
SELECT TRUNC('2024-01-15', 'MM');    -- 2024-01-01(月初)
SELECT TRUNC('2024-01-15', 'YY');    -- 2024-01-01(年初)
SELECT DATE_TRUNC('month', '2024-01-15 12:30:00');  -- 2024-01-01 00:00:00

-- 日期比较
SELECT GREATEST('2024-01-15', '2023-12-31');   -- 2024-01-15

10.4 条件函数

sql 复制代码
-- NVL / COALESCE(空值处理)
SELECT NVL(NULL, 'default');         -- default
SELECT NVL(null_col, 0) FROM table;  -- 替换 NULL 为 0
SELECT COALESCE(a, b, c, 'none');    -- 返回第一个非 NULL 值

-- IF
SELECT IF(salary > 10000, '高薪', '低薪') FROM employees;

-- IFF(Hive 2.0+)
SELECT IFF(score >= 60, 'pass', 'fail') FROM students;

-- NULLIF(相等则返回 NULL)
SELECT NULLIF(a, b);                  -- 若 a=b 则返回 NULL,否则返回 a

-- CASE WHEN(见查询章节)

-- ISNULL / ISNOTNULL
SELECT ISNULL(null_col) FROM table;  -- true/false

-- NVL2
SELECT NVL2(email, '有邮箱', '无邮箱') FROM employees;

-- DECODE(Oracle 兼容)
SELECT DECODE(status, 1, '有效', 0, '无效', '未知') FROM orders;

10.5 聚合函数

sql 复制代码
SELECT
  COUNT(*)            AS total_rows,
  COUNT(email)        AS non_null_emails,      -- 不统计 NULL
  COUNT(DISTINCT dept) AS unique_depts,
  SUM(salary)         AS total_salary,
  AVG(salary)         AS avg_salary,
  MAX(salary)         AS max_salary,
  MIN(salary)         AS min_salary,
  STDDEV_POP(salary)  AS std_salary,           -- 标准差(总体)
  VARIANCE(salary)    AS var_salary,            -- 方差
  COLLECT_SET(dept)   AS dept_set,             -- 收集唯一值到数组
  COLLECT_LIST(dept)  AS dept_list,            -- 收集所有值到数组(含重复)
  PERCENTILE(salary, 0.5)  AS median,          -- 中位数(数值列)
  PERCENTILE_APPROX(salary, 0.5) AS approx_median  -- 近似中位数(大数据)
FROM employees;

-- GROUP_CONCAT(类似 MySQL 的 GROUP_CONCAT)
SELECT dept, CONCAT_WS(',', COLLECT_LIST(name)) AS member_names
FROM employees
GROUP BY dept;

-- GROUPING SETS / CUBE / ROLLUP(多维聚合)
-- ROLLUP(层级聚合,等于多个 GROUP BY 结果的 UNION)
SELECT dept, job_level, SUM(salary)
FROM employees
GROUP BY dept, job_level WITH ROLLUP;

-- CUBE(所有维度组合)
SELECT dept, year, SUM(salary)
FROM employees
GROUP BY dept, year WITH CUBE;

-- GROUPING SETS(指定聚合维度)
SELECT dept, country, SUM(salary)
FROM employees
GROUP BY dept, country
GROUPING SETS ((dept, country), (dept), (country), ());

10.6 集合函数

sql 复制代码
SELECT
  SIZE(tags)            AS tag_count,          -- 数组/Map 的大小
  ARRAY_CONTAINS(tags, 'hadoop') AS has_hadoop, -- 是否包含元素
  SORT_ARRAY(tags)      AS sorted_tags,         -- 数组排序
  ARRAY_MIN(scores)     AS min_score,
  ARRAY_MAX(scores)     AS max_score,
  MAP_KEYS(props)       AS prop_keys,           -- Map 的键列表
  MAP_VALUES(props)     AS prop_values,         -- Map 的值列表
  STR_TO_MAP('a:1,b:2', ',', ':') AS prop_map  -- 字符串转 Map
FROM complex_table;

11. 用户自定义函数(UDF / UDAF / UDTF)

11.1 三类自定义函数对比

类型 全称 输入输出关系 典型内置示例 用途
UDF User Defined Function 一行输入 → 一行输出(1:1) UPPER(), LENGTH() 字段转换、计算
UDAF User Defined Aggregate Function 多行输入 → 一行输出(N:1) COUNT(), SUM() 自定义聚合计算
UDTF User Defined Table-Generating Function 一行输入 → 多行输出(1:N) EXPLODE(), JSON_TUPLE() 行展开、数组拆分

11.2 编写简单 UDF

java 复制代码
// 示例:将字符串中的手机号脱敏(替换中间4位为****)
package com.example.hive.udf;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

@Description(
    name = "mask_phone",
    value = "_FUNC_(phone) - Masks the middle 4 digits of phone number",
    extended = "Example: SELECT mask_phone('13812345678') FROM dual;"
)
public class MaskPhoneUDF extends UDF {

    public Text evaluate(Text phone) {
        if (phone == null) return null;
        String phoneStr = phone.toString();
        if (phoneStr.length() != 11) return phone;
        return new Text(phoneStr.substring(0, 3) + "****" + phoneStr.substring(7));
    }

    // 方法重载:处理多种输入类型
    public String evaluate(String phone) {
        if (phone == null || phone.length() != 11) return phone;
        return phone.substring(0, 3) + "****" + phone.substring(7);
    }
}
bash 复制代码
# 编译打包(Maven 方式)
mvn clean package -DskipTests
# 生成 target/my-hive-udf.jar
sql 复制代码
-- 在 Hive 中注册并使用 UDF

-- 方式1:临时函数(当前会话有效)
ADD JAR hdfs:///jars/my-hive-udf.jar;
CREATE TEMPORARY FUNCTION mask_phone AS 'com.example.hive.udf.MaskPhoneUDF';

-- 方式2:永久函数(写入 Metastore,所有会话可用)
-- 需先将 JAR 上传到 HDFS
CREATE FUNCTION mydb.mask_phone AS 'com.example.hive.udf.MaskPhoneUDF'
  USING JAR 'hdfs:///jars/my-hive-udf.jar';

-- 使用自定义函数
SELECT user_id, mask_phone(phone) AS masked_phone FROM users;

-- 查看已注册函数
SHOW FUNCTIONS LIKE 'mask*';
DESCRIBE FUNCTION mask_phone;
DESCRIBE FUNCTION EXTENDED mask_phone;

-- 删除函数
DROP TEMPORARY FUNCTION mask_phone;
DROP FUNCTION IF EXISTS mydb.mask_phone;

11.3 编写 GenericUDF(支持复杂类型)

java 复制代码
// GenericUDF:支持数组、Map、Struct 等复杂类型
package com.example.hive.udf;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;

@Description(name = "to_upper", value = "_FUNC_(str) - converts string to uppercase")
public class ToUpperGenericUDF extends GenericUDF {

    private StringObjectInspector stringOI;

    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        if (arguments.length != 1) {
            throw new UDFArgumentException("to_upper takes exactly one argument");
        }
        if (!(arguments[0] instanceof StringObjectInspector)) {
            throw new UDFArgumentTypeException(0, "to_upper argument must be a string");
        }
        this.stringOI = (StringObjectInspector) arguments[0];
        return PrimitiveObjectInspectorFactory.javaStringObjectInspector;  // 返回类型
    }

    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        String input = stringOI.getPrimitiveJavaObject(arguments[0].get());
        if (input == null) return null;
        return input.toUpperCase();
    }

    @Override
    public String getDisplayString(String[] children) {
        return "to_upper(" + children[0] + ")";
    }
}

11.4 编写 UDAF

java 复制代码
// UDAF:统计字符串列中字符总长度
package com.example.hive.udaf;

import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;

public class TotalLengthUDAF extends UDAF {

    public static class TotalLengthEvaluator implements UDAFEvaluator {
        private long total = 0;

        @Override
        public void init() { total = 0; }

        // 处理每行输入
        public boolean iterate(Text input) {
            if (input != null) total += input.getLength();
            return true;
        }

        // 返回部分聚合结果(Map 端输出)
        public LongWritable terminatePartial() {
            return new LongWritable(total);
        }

        // 合并部分结果(Reduce 端合并)
        public boolean merge(LongWritable partial) {
            if (partial != null) total += partial.get();
            return true;
        }

        // 返回最终结果
        public LongWritable terminate() {
            return new LongWritable(total);
        }
    }
}

11.5 编写 UDTF

java 复制代码
// UDTF:将 CSV 字符串拆分为多行
package com.example.hive.udtf;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.*;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import java.util.ArrayList;

public class SplitToRowsUDTF extends GenericUDTF {

    private PrimitiveObjectInspector stringOI;

    @Override
    public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
        // 定义输出列
        List<String> fieldNames = new ArrayList<>();
        List<ObjectInspector> fieldOIs = new ArrayList<>();
        fieldNames.add("value");
        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        this.stringOI = (PrimitiveObjectInspector) argOIs[0];
        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
    }

    @Override
    public void process(Object[] args) throws HiveException {
        String input = (String) stringOI.getPrimitiveJavaObject(args[0]);
        if (input != null) {
            String[] parts = input.split(",");
            for (String part : parts) {
                forward(new Object[]{part.trim()});  // 每个元素输出一行
            }
        }
    }

    @Override
    public void close() throws HiveException {}
}
sql 复制代码
-- 使用 UDTF
CREATE TEMPORARY FUNCTION split_to_rows AS 'com.example.hive.udtf.SplitToRowsUDTF'
  USING JAR 'hdfs:///jars/my-hive-udf.jar';

-- 直接使用
SELECT split_to_rows(tag_str) AS tag FROM raw_data;

-- 配合 LATERAL VIEW 使用
SELECT id, tag
FROM raw_data
LATERAL VIEW split_to_rows(tag_str) tmp AS tag;

12. Hive 执行引擎

12.1 三种执行引擎对比

特性 MapReduce Apache Tez Apache Spark
计算模型 Map + Reduce(两阶段) DAG(任意拓扑) DAG + 内存 RDD
中间结果 写磁盘 HDFS 写磁盘(可内存缓冲) 内存(可 spill 磁盘)
延迟 高(秒~分钟) 中(亚秒~秒) 低(亚秒)
复杂查询 多个 MR job,效率低 一个 DAG,高效 极高效
容错 Task 级重试 同 MR RDD 血缘重算
成熟度 最高 高(Hive 推荐)
Hive 推荐版本 Hive 1.x 默认 Hive 2.x+ 推荐 Hive on Spark

12.2 切换执行引擎

sql 复制代码
-- 查看当前执行引擎
SET hive.execution.engine;

-- 切换到 Tez(推荐,绝大多数生产环境)
SET hive.execution.engine=tez;

-- 切换到 Spark
SET hive.execution.engine=spark;

-- 切换回 MapReduce
SET hive.execution.engine=mr;

12.3 LLAP(Live Long and Process)

LLAP 是 Hive 2.0 引入的交互式查询加速功能:

复制代码
传统模式:提交查询 → 启动 JVM → 加载数据 → 执行 → 销毁 JVM(每次都有冷启动开销)
LLAP 模式:常驻的 Daemon 进程 → 缓存热数据(行列缓存) → 亚秒级响应

LLAP 核心特性:

  • 持久化的 Daemon(避免 JVM 冷启动)
  • 行列缓存(将 ORC/Parquet 热数据块缓存在内存)
  • 细粒度资源弹性(可根据负载动态调整)
  • 支持并发查询
sql 复制代码
-- 启用 LLAP(需要先部署 LLAP Daemons)
SET hive.llap.execution.mode = auto;

-- 在 hive-site.xml 中配置
-- hive.llap.daemon.memory.per.instance.mb=4096
-- hive.llap.daemon.vcpus.per.instance=4
-- hive.llap.io.enabled=true

13. Hive 性能调优

13.1 小文件合并

Hive 中小文件是最常见的性能问题之一,大量小文件会严重拖慢 NameNode 和 MapReduce 任务:

sql 复制代码
-- 方式1:查询时合并小文件(Map-Only 任务)
SET hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
SET mapreduce.input.fileinputformat.split.minsize=134217728;  -- 128MB
SET mapreduce.input.fileinputformat.split.maxsize=268435456;  -- 256MB

-- 方式2:输出时合并小文件
SET hive.merge.mapfiles=true;         -- 合并 Map-Only 任务输出
SET hive.merge.mapredfiles=true;      -- 合并 MapReduce 任务输出
SET hive.merge.size.per.task=268435456;       -- 目标合并文件大小 256MB
SET hive.merge.smallfiles.avgsize=134217728;  -- 触发合并的平均文件大小阈值

-- 方式3:定期手动合并(ORC 格式)
ALTER TABLE user_events PARTITION (dt='2024-01-01') CONCATENATE;

-- 方式4:Spark 重写(最彻底的方式)
INSERT OVERWRITE TABLE t PARTITION(dt='2024-01-01')
SELECT * FROM t WHERE dt='2024-01-01';

13.2 分区裁剪优化

sql 复制代码
-- ❌ 错误:分区条件在函数内,无法裁剪
SELECT * FROM user_events WHERE YEAR(dt) = 2024 AND MONTH(dt) = 1;

-- ✅ 正确:直接在分区列上使用字符串比较
SELECT * FROM user_events WHERE dt BETWEEN '2024-01-01' AND '2024-01-31';
SELECT * FROM user_events WHERE dt >= '2024-01-01' AND dt < '2024-02-01';

-- 验证分区裁剪是否生效
EXPLAIN SELECT * FROM user_events WHERE dt = '2024-01-01';
-- 在执行计划中查找 "partition filter"

-- 强制分区过滤(防止全表扫描)
SET hive.mapred.mode=strict;  -- 查询分区表时必须有分区条件,否则报错

13.3 MapJoin(小表 JOIN 优化)

sql 复制代码
-- 自动 MapJoin(Hive 自动判断小表)
SET hive.auto.convert.join=true;                    -- 默认 true
SET hive.mapjoin.smalltable.filesize=25000000;      -- 小表阈值:25MB
SET hive.auto.convert.join.noconditionaltask=true;
SET hive.auto.convert.join.noconditionaltask.size=10000000;  -- 10MB

-- 手动指定 MapJoin(HINT 方式)
SELECT /*+ MAPJOIN(d) */ e.name, d.dept_name
FROM employees e JOIN departments d ON e.dept_id = d.id;

-- Bucket Map Join(两表按相同列分桶,且桶数相同)
SET hive.optimize.bucketmapjoin=true;
SET hive.optimize.bucketmapjoin.sortedmerge=true;  -- SMB Join(最高效)

13.4 数据倾斜处理

数据倾斜是导致 Hive 作业长时间卡在 99% 的最常见原因。

sql 复制代码
-- 1. 开启倾斜 Join 优化
SET hive.optimize.skewjoin=true;
SET hive.skewjoin.key=100000;  -- 超过 10 万行认为是热点 key

-- 2. 随机前缀法(解决 GROUP BY 热点 key)
-- 第一步:加随机前缀,拆散热点 key
SELECT CONCAT(FLOOR(RAND() * 100), '_', user_id) AS rkey,
       SUM(amount) AS partial_sum
FROM orders GROUP BY CONCAT(FLOOR(RAND() * 100), '_', user_id);

-- 第二步:去掉前缀,再次聚合
SELECT SPLIT(rkey, '_')[1] AS user_id, SUM(partial_sum)
FROM (上面的子查询) t GROUP BY SPLIT(rkey, '_')[1];

-- 3. 过滤 NULL Key(NULL JOIN 时会全部分到同一 Reducer)
SELECT e.*, d.*
FROM employees e
JOIN departments d ON e.dept_id IS NOT NULL AND e.dept_id = d.id;

-- 4. 两阶段聚合(Map 端预聚合)
SET hive.map.aggr=true;           -- 开启 Map 端聚合(默认开启)
SET hive.groupby.skewindata=true; -- 倾斜数据随机分发到 Reducer(两次 MR)

13.5 Tez 引擎调优

sql 复制代码
-- Tez 容器大小(AM 和 Task 都用这个)
SET tez.am.resource.memory.mb=1024;
SET tez.task.resource.memory.mb=2048;
SET tez.task.launch.cmd-opts=-Xmx1800m;

-- 关闭 Tez Session(按需启动,节省资源)
SET tez.session.am.dag.submit.timeout.secs=600;

-- 开启预取优化
SET tez.runtime.enable.final-merge.in.output=true;

-- 增加并行度
SET hive.exec.parallel=true;                    -- 允许并行执行多个 Stage
SET hive.exec.parallel.thread.number=8;         -- 最大并行线程数

13.6 CBO(基于代价的优化器)

sql 复制代码
-- 启用 CBO(需要先收集统计信息)
SET hive.cbo.enable=true;                      -- 默认 true(Hive 0.14+)
SET hive.compute.query.using.stats=true;
SET hive.stats.fetch.column.stats=true;
SET hive.stats.fetch.partition.stats=true;

-- 收集统计信息(建议定期对重要表执行)
ANALYZE TABLE employees COMPUTE STATISTICS;                -- 表级别统计
ANALYZE TABLE employees COMPUTE STATISTICS FOR COLUMNS;   -- 列级别统计
ANALYZE TABLE user_events PARTITION (dt='2024-01-01') COMPUTE STATISTICS;

-- 查看统计信息
DESCRIBE FORMATTED employees;   -- 在输出中找 numRows、totalSize

-- 在 hive-site.xml 中启用自动统计收集
-- hive.stats.autogather=true  (INSERT/LOAD 后自动更新)

13.7 向量化执行

sql 复制代码
-- 开启向量化执行(一次处理 1024 行,利用 CPU SIMD 指令)
SET hive.vectorized.execution.enabled=true;         -- 默认 true(Hive 0.13+)
SET hive.vectorized.execution.reduce.enabled=true;
SET hive.vectorized.execution.reduce.groupby.enabled=true;

-- 查看向量化是否生效
EXPLAIN VECTORIZATION SELECT * FROM employees;

13.8 常见性能配置汇总

sql 复制代码
-- 一次性优化配置(可放入 hive-site.xml 或每次 Session 开始时执行)
SET hive.execution.engine=tez;
SET hive.auto.convert.join=true;
SET hive.cbo.enable=true;
SET hive.compute.query.using.stats=true;
SET hive.exec.parallel=true;
SET hive.exec.parallel.thread.number=8;
SET hive.vectorized.execution.enabled=true;
SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;
SET hive.merge.mapfiles=true;
SET hive.merge.mapredfiles=true;
SET hive.merge.size.per.task=256000000;
SET hive.map.aggr=true;
SET hive.groupby.skewindata=true;
SET hive.exec.compress.intermediate=true;
SET hive.exec.compress.output=true;

14. Hive 分区管理深入

14.1 静态分区 vs 动态分区

对比项 静态分区 动态分区
分区值 手动指定 查询时自动从数据中提取
速度 快(无需扫描分区列) 较慢(需要额外 Reducer)
使用场景 已知分区值,如按日期加载 分区值多或未知
语法 PARTITION (dt='2024-01-01') PARTITION (dt)
sql 复制代码
-- 静态分区
INSERT INTO TABLE user_events PARTITION (dt='2024-01-01', country='CN')
SELECT user_id, event_type, event_time, page_url
FROM raw_events_20240101;

-- 动态分区(分区列放在 SELECT 最后)
SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;
SET hive.exec.max.dynamic.partitions=1000;          -- 最大动态分区数
SET hive.exec.max.dynamic.partitions.pernode=300;   -- 每节点最大动态分区数

INSERT OVERWRITE TABLE user_events PARTITION (dt, country)
SELECT user_id, event_type, event_time, page_url, dt, country  -- dt 和 country 在最后
FROM raw_events;

14.2 分区命名规范建议

sql 复制代码
-- 推荐:字符串分区键,格式一致
PARTITIONED BY (dt STRING COMMENT 'date partition, format: yyyyMMdd')

-- 推荐:多级分区,粗粒度在前
PARTITIONED BY (year STRING, month STRING, day STRING)

-- 注意:分区值本身不存储在数据文件中,只体现在目录名中
-- 不建议将高基数列(如 user_id)作为分区键,会产生大量小文件

14.3 分区维护

sql 复制代码
-- 检查并修复分区(HDFS 目录存在但 Metastore 无记录)
MSCK REPAIR TABLE user_events;

-- 检查分区完整性
SHOW PARTITIONS user_events;

-- 查看特定分区的详情
DESCRIBE FORMATTED user_events PARTITION (dt='2024-01-01');

-- 交换分区(在两张相同结构的表间快速移动分区数据)
ALTER TABLE user_events EXCHANGE PARTITION (dt='2024-01-01') WITH TABLE user_events_staging;

-- 截断分区(仅清空数据,保留分区元数据)
TRUNCATE TABLE user_events PARTITION (dt='2023-01-01');

-- 归档分区(压缩为 Hadoop Archive 文件,减少小文件数量)
SET hive.archive.enabled=true;
ALTER TABLE user_events ARCHIVE PARTITION (dt='2023-01-01');
ALTER TABLE user_events UNARCHIVE PARTITION (dt='2023-01-01');

15. Hive 元数据服务(Metastore)

15.1 Metastore 三种部署模式

嵌入式模式(Embedded)
复制代码
Hive CLI ─── Driver ─── Metastore API ─── Derby(嵌入式数据库)
  • Derby 数据库随 Hive 进程一起启动
  • 只支持单连接
  • 仅适合学习和测试
本地模式(Local)
复制代码
Hive CLI ─── Driver ─── Metastore API ─── MySQL(同机)
  • Metastore 在 Hive 进程内运行,但使用外部 MySQL
  • 支持多连接,但每个 Hive 进程都直接连接数据库
  • 适合小型集群
远程模式(Remote,生产推荐)
复制代码
Hive Client 1 ─┐
Hive Client 2 ─┼─── Thrift Server ─── Metastore API ─── MySQL
Spark/Impala ──┘     (9083 端口)
  • Metastore 作为独立服务运行
  • 所有客户端通过 Thrift 协议连接
  • 支持多客户端并发
  • 数据库连接由 Metastore 服务统一管理

15.2 Metastore 重要配置

xml 复制代码
<!-- 元数据服务地址 -->
<property>
  <name>hive.metastore.uris</name>
  <value>thrift://metastore-host:9083</value>
</property>

<!-- 元数据库连接池配置 -->
<property>
  <name>datanucleus.connectionPoolingType</name>
  <value>DBCP</value>
</property>
<property>
  <name>datanucleus.connectionPool.maxPoolSize</name>
  <value>20</value>
</property>

<!-- 开启元数据缓存(减少 DB 查询) -->
<property>
  <name>hive.metastore.cache.pinobjtypes</name>
  <value>Table,StorageDescriptor,SerDeInfo,Partition,Database,Type,FieldSchema,Order</value>
</property>

<!-- Schema 版本兼容性检查 -->
<property>
  <name>hive.metastore.schema.verification</name>
  <value>true</value>
</property>

15.3 Metastore HA(高可用)

xml 复制代码
<!-- 配置多个 Metastore 实例实现高可用 -->
<property>
  <name>hive.metastore.uris</name>
  <value>thrift://metastore1:9083,thrift://metastore2:9083</value>
</property>

在多个节点上分别启动 Metastore 服务:

bash 复制代码
hive --service metastore &  # 在 metastore1 上
hive --service metastore &  # 在 metastore2 上

16. HiveServer2 与 Beeline

16.1 HiveServer2(HS2)

HiveServer2 是 Hive 提供远程多并发客户端访问的服务:

核心特性:

  • 多并发:支持多个客户端同时连接(HiveServer1 不支持)
  • 认证:Kerberos、LDAP、自定义认证
  • JDBC/ODBC 接口:标准 JDBC(端口 10000)
  • Web UI:默认 10002 端口,可监控 Sessions 和 Queries
bash 复制代码
# 启动 HiveServer2
hive --service hiveserver2 &
# 或者(推荐,重定向日志)
nohup $HIVE_HOME/bin/hiveserver2 > /var/log/hive/hiveserver2.log 2>&1 &

# 查看 Web UI
http://localhost:10002

16.2 Beeline 使用详解

Beeline 是基于 JDBC 的 HiveServer2 客户端,推荐替代旧的 Hive CLI:

bash 复制代码
# 连接方式1:本地连接(不需要认证)
beeline -u jdbc:hive2://localhost:10000

# 连接方式2:指定用户名密码
beeline -u jdbc:hive2://localhost:10000 -n hive -p password

# 连接方式3:Kerberos 认证
beeline -u "jdbc:hive2://localhost:10000/default;principal=hive/hostname@REALM"

# 连接方式4:指定数据库
beeline -u jdbc:hive2://localhost:10000/mydb

# 非交互式:执行单个查询后退出
beeline -u jdbc:hive2://localhost:10000 -e "SELECT COUNT(*) FROM employees"

# 非交互式:执行 SQL 脚本文件
beeline -u jdbc:hive2://localhost:10000 -f /path/to/script.hql

# 关闭 beeline header 和 footer(适合脚本解析)
beeline --silent=true --outputformat=tsv2 -u jdbc:hive2://localhost:10000 \
  -e "SELECT * FROM employees" > output.tsv

Beeline 交互式命令:

sql 复制代码
-- 连接到 HiveServer2
!connect jdbc:hive2://localhost:10000

-- 断开连接
!disconnect

-- 退出
!quit

-- 查看所有命令
!help

-- 查看当前连接信息
!info

-- 执行 Shell 命令
!sh ls /data/

-- 查看历史命令
!history

-- 设置输出格式
!set outputformat table      -- 表格(默认)
!set outputformat csv2       -- CSV
!set outputformat tsv2       -- TSV
!set outputformat json       -- JSON

-- 显示/隐藏列 Header
!set headerInterval 0        -- 只显示一次 Header
!set showHeader true/false

-- 设置最大行宽
!set maxWidth 200
!set maxColumnWidth 50

16.3 JDBC 程序连接 Hive

java 复制代码
import java.sql.*;

public class HiveJDBCExample {
    private static final String JDBC_URL = "jdbc:hive2://localhost:10000/default";
    private static final String DRIVER_CLASS = "org.apache.hive.jdbc.HiveDriver";

    public static void main(String[] args) throws Exception {
        Class.forName(DRIVER_CLASS);

        try (Connection conn = DriverManager.getConnection(JDBC_URL, "hive", "");
             Statement stmt = conn.createStatement()) {

            // 创建表
            stmt.execute("CREATE TABLE IF NOT EXISTS test_jdbc (id INT, name STRING) STORED AS ORC");

            // 插入数据
            stmt.execute("INSERT INTO test_jdbc VALUES (1, 'Alice'), (2, 'Bob')");

            // 查询
            try (ResultSet rs = stmt.executeQuery("SELECT * FROM test_jdbc")) {
                ResultSetMetaData metaData = rs.getMetaData();
                while (rs.next()) {
                    for (int i = 1; i <= metaData.getColumnCount(); i++) {
                        System.out.print(rs.getString(i) + "\t");
                    }
                    System.out.println();
                }
            }
        }
    }
}

Maven 依赖:

xml 复制代码
<dependency>
  <groupId>org.apache.hive</groupId>
  <artifactId>hive-jdbc</artifactId>
  <version>3.1.3</version>
</dependency>

17. Hive 安全机制

17.1 认证方式

认证方式 适用场景 配置方式
无认证 开发/测试 默认
LDAP 企业 Active Directory 集成 hive.server2.authentication=LDAP
Kerberos 企业生产安全环境 hive.server2.authentication=KERBEROS
Custom 自定义认证插件 hive.server2.authentication=CUSTOM
PAM Linux PAM 认证 hive.server2.authentication=PAM
xml 复制代码
<!-- Kerberos 认证配置示例 -->
<property>
  <name>hive.server2.authentication</name>
  <value>KERBEROS</value>
</property>
<property>
  <name>hive.server2.kerberos.principal</name>
  <value>hive/_HOST@YOUR-REALM.COM</value>
</property>
<property>
  <name>hive.server2.kerberos.keytab</name>
  <value>/etc/security/keytabs/hive.service.keytab</value>
</property>

17.2 授权机制

sql 复制代码
-- Hive 内置权限控制(基于 SQL 标准)
-- 启用(hive-site.xml 中):
-- hive.security.authorization.enabled=true
-- hive.security.authorization.manager=org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory

-- 创建角色
CREATE ROLE analyst;
CREATE ROLE data_engineer;

-- 授予角色权限
GRANT SELECT ON DATABASE sales_db TO ROLE analyst;
GRANT ALL ON TABLE employees TO ROLE data_engineer;
GRANT SELECT ON TABLE employees (name, dept) TO ROLE analyst;  -- 列级权限

-- 将角色赋予用户
GRANT ROLE analyst TO USER alice;
GRANT ROLE data_engineer TO USER bob;

-- 撤销权限
REVOKE SELECT ON DATABASE sales_db FROM ROLE analyst;
REVOKE ROLE analyst FROM USER alice;

-- 查看权限
SHOW GRANT USER alice ON TABLE employees;
SHOW ROLE GRANT USER alice;
SHOW GRANTS ON TABLE employees;

-- 删除角色
DROP ROLE analyst;

17.3 与 Apache Ranger 集成

Apache Ranger 提供企业级细粒度权限控制:

复制代码
用户请求 → HiveServer2 → Ranger 插件鉴权 → 允许/拒绝
                                ↑
                         Ranger Admin(策略管理中心)
                                ↑
                         Ranger Audit(审计日志)

Ranger 支持:

  • 数据库/表/列/行级别权限控制
  • 基于用户/组/角色的权限策略
  • 数据掩码(敏感数据自动脱敏)
  • 行过滤(不同用户看到不同行)
  • 完整的审计日志

18. Hive 与生态系统集成

18.1 Hive on Spark

bash 复制代码
# 在 hive-site.xml 中配置
# hive.execution.engine=spark
# spark.master=yarn
# spark.submit.deployMode=cluster
sql 复制代码
-- 切换到 Spark 引擎
SET hive.execution.engine=spark;

-- Spark 相关配置
SET spark.executor.memory=4g;
SET spark.executor.cores=2;
SET spark.executor.instances=10;
SET spark.dynamicAllocation.enabled=true;

-- 执行查询(透明使用 Spark 计算)
SELECT dept, AVG(salary) FROM employees GROUP BY dept;

18.2 与 Spark SQL 共享 Metastore

Spark SQL 和 Hive 可以共享同一个 Metastore,让两个系统看到相同的表结构:

scala 复制代码
// Spark 代码中配置 Hive Metastore
val spark = SparkSession.builder()
  .appName("HiveIntegration")
  .config("spark.sql.warehouse.dir", "/user/hive/warehouse")
  .config("hive.metastore.uris", "thrift://localhost:9083")
  .enableHiveSupport()
  .getOrCreate()

// 直接查询 Hive 表
spark.sql("SELECT * FROM sales_db.orders LIMIT 10").show()

// Spark 写入的表在 Hive 中可见
spark.sql("""
  CREATE TABLE IF NOT EXISTS spark_result
  USING ORC
  AS SELECT dept, SUM(salary) FROM employees GROUP BY dept
""")

18.3 与 HBase 集成

sql 复制代码
-- 创建 Hive-HBase 映射表(通过 HBase StorageHandler)
CREATE TABLE hbase_users (
  key       STRING,
  name      STRING,
  age       INT,
  email     STRING
)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
  'hbase.columns.mapping' = ':key,info:name,info:age,info:email'
)
TBLPROPERTIES ('hbase.table.name' = 'users');

-- 通过 Hive 查询 HBase 数据
SELECT * FROM hbase_users WHERE key = 'user001';

18.4 与 Apache Iceberg 集成(Hive 4.x)

Apache Iceberg 是新一代开放表格式,Hive 4.x 对其提供原生支持:

sql 复制代码
-- 创建 Iceberg 表
CREATE TABLE iceberg_orders (
  order_id  BIGINT,
  user_id   INT,
  amount    DECIMAL(10,2),
  status    STRING,
  create_ts TIMESTAMP
)
STORED BY 'org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'
LOCATION '/warehouse/iceberg/orders'
TBLPROPERTIES (
  'table_type'='ICEBERG',
  'format-version'='2',              -- Iceberg v2(支持 Row-level Updates)
  'write.delete.mode'='merge-on-read' -- 删除模式
);

-- Iceberg 支持的时间旅行(Time Travel)
-- 查询历史快照
SELECT * FROM iceberg_orders FOR SYSTEM_TIME AS OF '2024-01-01 00:00:00';
SELECT * FROM iceberg_orders FOR SYSTEM_VERSION AS OF 12345678;

-- 查看表历史
SELECT * FROM iceberg_orders.history;
SELECT * FROM iceberg_orders.snapshots;

-- Iceberg Z-order 排序(Hive 4.x 新特性)
ALTER TABLE iceberg_orders EXECUTE OPTIMIZE(ZORDER BY (user_id, create_ts));

18.5 与 Sqoop 集成

bash 复制代码
# Sqoop 从 MySQL 导入数据到 Hive 表
sqoop import \
  --connect jdbc:mysql://mysql-host:3306/sales \
  --username root --password secret \
  --table orders \
  --hive-import \
  --hive-database sales_db \
  --hive-table orders_from_mysql \
  --hive-overwrite \
  --num-mappers 4

# Sqoop 将 Hive 表数据导出到 MySQL
sqoop export \
  --connect jdbc:mysql://mysql-host:3306/sales \
  --username root --password secret \
  --table mysql_target \
  --hcatalog-database sales_db \
  --hcatalog-table hive_source

19. Hive 4.x 新特性

19.1 Iceberg v3 深度集成

sql 复制代码
-- 支持 Iceberg v3 功能:Deletion Vectors(删除向量)
-- 比 MoR 模式更高效的行级删除实现
CREATE TABLE orders_v3 (...)
STORED BY 'org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'
TBLPROPERTIES (
  'format-version'='3',
  'write.delete.mode'='merge-on-read'
);

-- Z-ordering 优化(空间近邻填充曲线,提升多列过滤性能)
ALTER TABLE orders_v3 EXECUTE OPTIMIZE(ZORDER BY (user_id, date));

-- Variant 类型(半结构化数据,类似 JSON Schema)
CREATE TABLE semi_struct (id BIGINT, data VARIANT);

19.2 JDK 21 支持

Hive 4.x 支持 Java 21,可使用虚拟线程(Virtual Threads)提升 HS2 并发性能。

19.3 HMS REST Catalog

sql 复制代码
-- Hive Metastore 暴露 REST API,兼容 Apache Iceberg REST Catalog 协议
-- 允许 Spark、Flink 通过标准 REST API 访问 Hive 元数据

19.4 内置自动 Compaction

Hive 4.x 加入了 ACID 表的自动 Compaction 功能,无需手动触发:

sql 复制代码
-- 查看 compaction 队列
SHOW COMPACTIONS;

-- 手动触发 compaction(Major:合并所有增量到基础文件)
ALTER TABLE student COMPACT 'major';

-- 手动触发 Minor compaction(合并增量文件)
ALTER TABLE student COMPACT 'minor';

20. 常见问题与排查

20.1 Hive 查询卡住不动

排查步骤:

bash 复制代码
# 1. 查看 YARN 作业状态
yarn application -list
yarn application -status <application_id>

# 2. 查看 Hive 日志
tail -f $HIVE_HOME/logs/hive.log

# 3. 查看 YARN 作业日志
yarn logs -applicationId application_XXXXX

# 4. 检查是否有 Reducer 数据倾斜(YARN UI http://master:8088 中查看各 Reducer 进度)

20.2 "Too many dynamic partitions" 错误

sql 复制代码
-- 错误信息:Number of dynamic partitions created is 2000, which is more than 1000
-- 解决:增大动态分区限制
SET hive.exec.max.dynamic.partitions=5000;
SET hive.exec.max.dynamic.partitions.pernode=1000;

20.3 Out of Memory 错误

sql 复制代码
-- 增大 Map/Reduce 内存
SET mapreduce.map.memory.mb=4096;
SET mapreduce.reduce.memory.mb=8192;
SET mapreduce.map.java.opts=-Xmx3276m;
SET mapreduce.reduce.java.opts=-Xmx6553m;

-- 增大 Tez 容器大小
SET tez.task.resource.memory.mb=4096;
SET tez.task.launch.cmd-opts=-Xmx3276m;

20.4 Metastore 连接失败

bash 复制代码
# 检查 Metastore 服务是否运行
netstat -tuln | grep 9083
# 或
ps aux | grep HiveMetaStore

# 重启 Metastore
pkill -f HiveMetaStore
nohup hive --service metastore > /tmp/metastore.log 2>&1 &

# 检查 MySQL 连接
mysql -h localhost -u hive -p metastore

# 检查 schema 版本
schematool -dbType mysql -info

20.5 "Unable to move source" 错误

bash 复制代码
# 原因:HDFS 临时目录权限问题
hdfs dfs -chmod 777 /tmp/hive
hdfs dfs -chown -R hive:hdfs /user/hive/warehouse

# 在 hive-site.xml 中设置 hive 临时目录
# hive.exec.scratchdir=/tmp/hive
# hive.downloaded.resources.dir=/tmp/hive/resources

20.6 全表扫描警告

sql 复制代码
-- 错误:Strict mode requires that a partition filter is present before returning from this call
-- 原因:hive.mapred.mode=strict 时,查询分区表必须有分区条件

-- 解决方案1:添加分区条件
SELECT * FROM user_events WHERE dt = '2024-01-01';

-- 解决方案2:临时关闭 strict 模式
SET hive.mapred.mode=nonstrict;

20.7 Join 内存溢出(小表 MapJoin 失败)

sql 复制代码
-- 增大 MapJoin 阈值
SET hive.mapjoin.smalltable.filesize=128000000;  -- 128MB
SET hive.auto.convert.join.noconditionaltask.size=128000000;

-- 或关闭自动 MapJoin,改用普通 Join
SET hive.auto.convert.join=false;

21. 最佳实践总结

21.1 建表规范

sql 复制代码
-- ✅ 推荐建表模式
CREATE TABLE sales_order (
  order_id    BIGINT      COMMENT '订单ID(主键)',
  user_id     INT         COMMENT '用户ID',
  product_id  INT         COMMENT '商品ID',
  amount      DECIMAL(12,2) COMMENT '订单金额',
  create_ts   TIMESTAMP   COMMENT '下单时间'
)
COMMENT '销售订单明细表'
PARTITIONED BY (dt STRING COMMENT '日期分区 yyyyMMdd')
STORED AS ORC
TBLPROPERTIES (
  'orc.compress'='SNAPPY',
  'author'='data_eng_team',
  'create_time'='2024-01-01'
);

21.2 数据导入规范

bash 复制代码
# 1. 批量数据:使用 LOAD DATA 或 INSERT OVERWRITE
# 2. 增量数据:INSERT INTO(追加)
# 3. 大批量 ETL:INSERT OVERWRITE TABLE ... SELECT ...(效率最高)
# 4. 导入后运行 ANALYZE TABLE 收集统计信息

21.3 查询优化清单

复制代码
□ 分区表查询必须包含分区条件
□ 优先使用 ORC 或 Parquet 格式
□ 小表 JOIN 使用 MAPJOIN hint
□ 避免 SELECT *,只查需要的列
□ GROUP BY 使用高基数列(低基数考虑分桶后 SMB Join)
□ 使用 EXPLAIN 分析执行计划
□ 对核心表执行 ANALYZE TABLE 收集统计信息
□ 避免在 WHERE 条件中对分区列使用函数
□ 大查询优先使用 Tez 引擎
□ 数据倾斜时使用 hive.groupby.skewindata=true

21.4 EXPLAIN 使用

sql 复制代码
-- 查看执行计划
EXPLAIN SELECT dept, COUNT(*) FROM employees WHERE salary > 10000 GROUP BY dept;

-- 查看详细执行计划(含操作符树)
EXPLAIN EXTENDED SELECT ...;

-- 查看依赖关系
EXPLAIN DEPENDENCY SELECT ...;

-- 查看向量化信息
EXPLAIN VECTORIZATION SELECT ...;

-- 查看 CBO 相关信息(需 SET hive.cbo.enable=true)
EXPLAIN ANALYZE SELECT ...;

21.5 Hive 命令行技巧

bash 复制代码
# 执行单个 HQL 后退出
hive -e "SELECT COUNT(*) FROM employees"

# 执行 HQL 脚本文件
hive -f /data/scripts/report.hql

# 传递变量到 HQL 脚本(使用 hiveconf)
hive -f report.hql --hiveconf dt=2024-01-01
# 在 HQL 中使用:WHERE dt = '${hiveconf:dt}'

# 静默模式(去掉 INFO 日志)
hive -S -e "SELECT ..."

# 初始化 HQL(每次启动时执行)
hive --hiveconf hive.session.id=mysession -i /data/scripts/init.hql -f report.hql

22. Hive 与其他技术对比

22.1 Hive vs Spark SQL

对比维度 Hive(+Tez) Spark SQL
擅长场景 超大批量 ETL,PB 级离线处理 复杂分析,迭代计算,ML 管道
查询延迟 秒~分钟级 亚秒~秒级
内存使用 磁盘为主,内存需求低 内存密集型
SQL 兼容 HiveQL(HQL),自己的方言 ANSI SQL,兼容 HiveQL
生态整合 Hadoop 原生,Metastore 标准 支持 Hive Metastore
小文件处理 需要手动合并 自动处理能力强
流批一体 仅批处理 批处理 + Structured Streaming

22.2 Hive vs Presto/Trino

对比维度 Hive Presto/Trino
定位 批处理 ETL 工具 交互式 OLAP 查询引擎
延迟 高(秒~分钟) 低(毫秒~秒,MPP 并行)
数据源 HDFS/S3/HBase 多源联邦:Hive/MySQL/S3/Kafka 等
大数据集 擅长(PB 级 ETL) 内存有限,超大结果集可能 OOM
SQL 支持 HiveQL 扩展 接近标准 ANSI SQL
使用场景 数据入库、转换、批量报表 BI 即席查询、实时大屏

22.3 Hive vs Impala

对比维度 Hive Impala
架构 MapReduce/Tez/Spark 执行 原生 MPP,C++ 实现
延迟 低(内存 MPP,毫秒级)
容错 强(MR/Tez 容错机制) 弱(查询失败需重试)
UDF Java/Python Java(有限)
共享 Metastore 是(HMS) 是(共享 Hive HMS)
适用场景 大批量 ETL 快速分析查询

22.4 2024 年 Hive 的定位

Hive 在现代数据栈中的核心价值仍然存在:

复制代码
数据湖架构中的 Hive 角色(2024):

存储层:  HDFS / S3 / OSS(对象存储)
表格式:  Hive 表 / Apache Iceberg / Apache Hudi / Apache Delta Lake
批处理:  Hive(ETL)/ Spark(复杂计算)
即席查询:Presto / Trino / Spark SQL
元数据:  Hive Metastore(HMS,事实上的行业标准)

HMS(Hive Metastore Service)已成为大数据生态的元数据中枢,即使不使用 Hive 做查询,Spark、Presto、Flink 等都依赖 HMS 管理表元数据。这是 Hive 在现代架构中最核心的价值所在。


23. 附录:配置项速查 & 官方资源

23.1 重要配置项汇总

配置项 默认值 说明
hive.execution.engine mr 执行引擎:mr/tez/spark
hive.metastore.warehouse.dir /user/hive/warehouse Hive 仓库目录
hive.exec.dynamic.partition false 是否启用动态分区
hive.exec.dynamic.partition.mode strict 动态分区模式:strict/nonstrict
hive.exec.max.dynamic.partitions 1000 最大动态分区数
hive.auto.convert.join true 自动转换 MapJoin
hive.mapjoin.smalltable.filesize 25MB MapJoin 小表阈值
hive.cbo.enable true 启用 CBO 优化器
hive.vectorized.execution.enabled true 启用向量化执行
hive.exec.parallel false 并行执行多个 Stage
hive.merge.mapfiles true 合并 Map-only 输出小文件
hive.merge.mapredfiles false 合并 MR 输出小文件
hive.groupby.skewindata false 数据倾斜时随机分发
hive.map.aggr true Map 端预聚合
hive.mapred.mode nonstrict strict 模式强制分区条件
hive.optimize.skewjoin false 倾斜 Join 优化
hive.server2.thrift.port 10000 HiveServer2 端口
hive.metastore.port 9083 Metastore Thrift 端口
hive.server2.webui.port 10002 HiveServer2 Web UI 端口

23.2 默认端口速查

服务 端口 协议
Hive Metastore 9083 Thrift
HiveServer2(JDBC/ODBC) 10000 Thrift/HTTP
HiveServer2 Web UI 10002 HTTP
Hive CLI(本地) - 本地进程

23.3 官方资源链接

资源 URL
Apache Hive 官网 https://hive.apache.org/
官方 Wiki 文档 https://cwiki.apache.org/confluence/display/Hive/Home
Hive 下载页面 https://hive.apache.org/downloads.html
快速开始指南 https://hive.apache.org/development/quickstart/
语言手册(DDL) https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL
语言手册(DML) https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML
语言手册(UDF) https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
设计文档 https://hive.apache.org/development/desingdocs/design/
管理员手册 https://hive.apache.org/docs/latest/admin/
HiveServer2 文档 https://cwiki.apache.org/confluence/display/Hive/Setting+Up+HiveServer2
Hive GitHub https://github.com/apache/hive

23.4 常用 SQL 速查

sql 复制代码
-- 查看当前配置
SET hive.execution.engine;           -- 查看单个配置
SET;                                  -- 查看所有配置

-- 查看当前数据库
SELECT current_database();

-- 查看 Hive 版本
SELECT version();

-- 查看函数列表
SHOW FUNCTIONS;
SHOW FUNCTIONS LIKE 'str*';

-- 查看建表语句
SHOW CREATE TABLE table_name;

-- 查看分区列表
SHOW PARTITIONS table_name;

-- 查看锁
SHOW LOCKS table_name;

-- 释放锁
UNLOCK TABLE table_name;

-- 查看正在运行的查询(HS2 Web UI)
-- http://localhost:10002/queries

-- 执行计划
EXPLAIN [EXTENDED|VECTORIZATION|DEPENDENCY|AUTHORIZATION|ANALYZE] query;
相关推荐
Elastic 中国社区官方博客4 小时前
当 TSDS 遇到 ILM:设计不会拒绝延迟数据的时间序列数据流
大数据·运维·数据库·elasticsearch·搜索引擎·logstash
Omics Pro4 小时前
虚拟细胞:开启HIV/AIDS治疗新纪元的关键?
大数据·数据库·人工智能·深度学习·算法·机器学习·计算机视觉
沐风___5 小时前
Claude Code 权限模式完全指南:Auto、Bypass、Ask 三模式深度解析
大数据·elasticsearch·搜索引擎
qq_5470261796 小时前
LangChain 工具调用(Tool Calling)
java·大数据·langchain
黎阳之光8 小时前
黎阳之光:数智科技破局湖库富营养化,筑造水生态治理新标杆
大数据·人工智能·科技·安全·数字孪生
算法即正义9 小时前
知识竞赛在党建教育中的创新应用:激活学习动能,赋能组织活力
大数据·人工智能
Elastic 中国社区官方博客9 小时前
使用 Elastic Workflows 监控 Kibana 仪表板视图
大数据·运维·数据库·elasticsearch·搜索引擎·全文检索·kibana
ggabb10 小时前
中国科技发展与华人贡献解析
大数据·人工智能
乐迪信息11 小时前
乐迪信息:船舶AI逆行检测算法在单向航道中的强制管控
大数据·人工智能·安全·计算机视觉·目标跟踪