Hive学习笔记
一、Hive基础认知
1.1 什么是Hive
Hive是基于Hadoop的数据仓库工具,本质是将SQL转化为MapReduce(或Tez、Spark)任务来执行,核心用于处理大规模结构化/半结构化数据的存储与分析,不适合实时计算(延迟较高)。
核心定位:SQL on Hadoop,让不熟悉MapReduce的开发者能通过SQL操作HDFS上的数据。
1.2 Hive的核心架构(5大组件)
-
用户接口(Client):提供用户操作入口,常见3种:
-
CLI(命令行界面):最常用,直接输入Hive SQL执行
-
Web UI:通过浏览器访问,直观查看任务和数据
-
JDBC/ODBC:用于Java程序或其他工具(如DataGrip)连接Hive
-
-
元数据存储(Metastore):
-
存储Hive的核心元数据(表结构、分区信息、数据库信息、表与HDFS文件的映射关系等)
-
默认存储在Derby数据库(单用户,适合测试),生产环境常用MySQL(多用户共享,稳定可靠)
-
元数据是Hive的"大脑",丢失会导致无法关联数据文件
-
-
驱动(Driver):接收用户SQL,拆解为执行步骤,核心包含2个模块:
-
解析器(Parser):检查SQL语法正确性,生成抽象语法树(AST)
-
优化器(Optimizer):对AST进行优化(如分区裁剪、Join优化),生成最优执行计划
-
-
执行引擎(Execution Engine):将优化后的执行计划转化为底层计算框架的任务(默认MapReduce,可配置为Tez/Spark),提交到Hadoop集群执行。
-
Hadoop集群:Hive的底层依赖,负责实际的数据存储(HDFS)和计算(MapReduce/Tez/Spark)。
1.3 Hive与Hadoop的关系
Hive依赖Hadoop,不能独立运行:
-
HDFS:存储Hive的所有数据(表数据、日志等)
-
MapReduce/Tez/Spark:执行Hive SQL转化后的计算任务
区别:Hadoop是分布式存储+计算框架,Hive是基于Hadoop的数据仓库工具,专注于数据的结构化分析。
1.4 Hive的特点
-
优点:易用性(SQL语法)、可扩展性(支持大规模数据)、容错性(依赖Hadoop的容错机制)、低成本(复用Hadoop集群)
-
缺点:实时性差(批处理为主,延迟分钟/小时级)、不适合小数据量计算(启动MapReduce任务耗时久)、不支持事务(默认,Hive 3.0+支持有限事务)
二、Hive环境搭建(核心步骤)
2.1 搭建前提
已搭建好Hadoop集群(HDFS+YARN),且集群正常运行;JDK环境配置完成(推荐JDK8)。
2.2 搭建方式(3种,重点掌握前2种)
(1)单机模式(适合测试)
-
元数据存储在默认的Derby数据库,仅支持单用户访问
-
核心步骤:解压Hive安装包 → 配置环境变量 → 初始化元数据(schematool -dbType derby -initSchema) → 启动Hive CLI
(2)伪分布式模式(常用,模拟集群)
-
元数据存储在MySQL数据库(多用户可访问),Hive服务和Hadoop集群部署在同一台机器
-
核心步骤:
-
解压Hive安装包,配置环境变量(HIVE_HOME、PATH)
-
修改核心配置文件(hive-env.sh、hive-site.xml):
-
hive-env.sh:指定HADOOP_HOME路径
-
hive-site.xml:配置MySQL连接信息(驱动、URL、用户名、密码)、元数据存储路径、HDFS临时路径
-
-
将MySQL驱动包(mysql-connector-java.jar)放入Hive的lib目录
-
初始化元数据(schematool -dbType mysql -initSchema)
-
启动Hive(CLI或hiveserver2)
-
(3)分布式模式(生产环境)
Hive服务(metastore、hiveserver2)部署在单独节点,元数据存储在远程MySQL,Hadoop集群为独立集群,适合多用户、大规模数据场景。
- 在hive安装的服务器上,首先启动metastore服务,然后启动hiveserver2服务。
python
#先启动metastore服务 然后启动hiveserver2服务
nohup bin/hive --service metastore >> logs/metastore.log 2>&1 &
nohup bin/hive --service hiveserver2 >> logs/hiveserver2.log 2>&1 &
2.3 常用启动命令
-
启动Hive CLI:hive
-
启动HiveServer2(支持JDBC/ODBC连接):hiveserver2(后台启动:nohup hiveserver2 &)
-
beeline连接HiveServer2:beeline -u jdbc:hive2://localhost:10000 -n 用户名
-
初始化元数据:schematool -dbType 数据库类型(derby/mysql) -initSchema
-
查看Hive版本:hive --version
三、Hive核心概念(必掌握)
3.1 数据库(Database)
Hive中的数据库本质是目录(Namespace),用于隔离表(避免表名冲突),对应HDFS上的一个目录(默认路径:/user/hive/warehouse/数据库名.db)。
默认数据库:default,没有单独的HDFS目录,表直接存储在/user/hive/warehouse下。
3.2 表(Table)
Hive的表对应HDFS上的一个目录(或文件),表结构定义了数据的字段、类型、分隔符等,核心分为2类表:管理表(Managed Table)和外部表(External Table)(重点区分)。
(1)管理表(内部表)
-
表数据由Hive管理,表对应的HDFS目录默认在数据库目录下(/user/hive/warehouse/数据库名.db/表名)
-
删除表(DROP TABLE)时,会同时删除表结构和HDFS上的表数据
-
适用场景:临时表、中间表(数据仅用于Hive内部计算,无需保留)
(2)外部表
-
表数据由用户管理,创建表时需指定数据的HDFS路径(LOCATION关键字)
-
删除表(DROP TABLE)时,仅删除表结构,不删除HDFS上的表数据,数据可被其他工具复用
-
适用场景:多工具共享数据(如Hive和Spark共用一份数据)、核心业务数据(避免误删数据)
管理表与外部表的核心区别
| 对比维度 | 管理表 | 外部表 |
|---|---|---|
| 数据管理权 | Hive管理 | 用户管理 |
| HDFS路径 | 默认路径(warehouse下) | 自定义路径(LOCATION指定) |
| 删除表影响 | 删除表结构+数据 | 仅删除表结构 |
| 适用场景 | 临时表、中间表 | 共享数据、核心数据 |
(3)分区表(Partition Table)
-
核心目的:减少查询时扫描的数据量(分区裁剪),将大表按指定字段(如日期、地区)拆分多个小目录。
-
原理:分区字段不存储在表数据中,仅作为HDFS目录的名称,查询时指定分区可直接定位到对应目录,避免全表扫描。
-
示例:按日期分区存储日志表,目录结构为:/user/hive/warehouse/log.db/log_table/day=2024-01-01、/day=2024-01-02...
-
注意:分区字段可以是多个(多级分区),如day=2024-01-01/hour=08。
(4)分桶表(Bucket Table)
-
核心目的:优化Join操作(分桶连接,Map Join的一种优化),将表数据按指定字段的哈希值拆分到多个文件(桶)中。
-
原理:分桶字段哈希取模(mod)桶的数量,相同哈希值的数据放入同一个桶,Join时仅需关联对应桶的数据,减少数据 shuffle。
-
示例:将用户表按user_id分桶为8个桶,每个桶存储user_id哈希值 mod 8 等于对应值的数据。
-
注意:分桶表的数据需要通过INSERT OVERWRITE加载(不能直接LOAD DATA),且需开启分桶功能(hive.enforce.bucketing=true)。
3.3 数据类型
(1)基本数据类型(常用)
-
数值型:TINYINT(1字节)、SMALLINT(2字节)、INT(4字节)、BIGINT(8字节)、FLOAT(单精度)、DOUBLE(双精度)
-
字符串型:STRING(可变长度,无长度限制)、VARCHAR(固定长度,需指定长度)、CHAR(固定长度,默认1字节)
-
布尔型:BOOLEAN(true/false)
-
日期型:DATE(日期,如2024-01-01)、TIMESTAMP(时间戳,如2024-01-01 12:00:00)
(2)复杂数据类型(重点)
-
ARRAY:数组,存储相同类型的集合,如array(存储姓名列表),访问方式:数组名[索引](索引从0开始)
-
MAP:键值对集合,如map<STRING, INT>(存储姓名-年龄),访问方式:map名['键名']
-
STRUCT:结构体,存储不同类型的字段,如struct<name:STRING, age:INT>,访问方式:结构体名.字段名
-
示例:字段定义为 info struct<name:string, score:array>,访问分数列表:info.score,访问第一个分数:info.score[0]
3.4 分隔符
Hive表数据是文本文件(默认),需要指定字段之间、复杂类型内部的分隔符,否则会解析失败,常用分隔符如下:
-
字段分隔符:默认^A(Ctrl+A),可用FIELDS TERMINATED BY指定(如逗号、制表符\t)
-
数组/结构体内部分隔符:默认^B(Ctrl+B),可用COLLECTION ITEMS TERMINATED BY指定
-
MAP键值分隔符:默认^C(Ctrl+C),可用MAP KEYS TERMINATED BY指定
-
行分隔符:默认\n(换行符),一般无需指定
四、Hive SQL实操(核心重点)
4.1 数据库操作(DDL)
(1)创建数据库
sql
-- 基本创建
CREATE DATABASE IF NOT EXISTS db_name;
-- 指定HDFS路径(可选)
CREATE DATABASE IF NOT EXISTS db_name
LOCATION '/user/hive/warehouse/db_name.db';
-- 添加描述(可选)
CREATE DATABASE IF NOT EXISTS db_name
COMMENT '这是一个测试数据库'
LOCATION '/user/hive/warehouse/db_name.db';
(2)查看数据库
sql
-- 查看所有数据库
SHOW DATABASES;
-- 查看数据库详情
DESCRIBE DATABASE db_name;
-- 查看数据库详情(包括路径)
DESCRIBE DATABASE EXTENDED db_name;
(3)切换数据库
sql
USE db_name;
(4)删除数据库
sql
-- 仅删除空数据库(若有表,删除失败)
DROP DATABASE IF EXISTS db_name;
-- 强制删除(删除数据库及所有表)
DROP DATABASE IF EXISTS db_name CASCADE;
4.2 表操作(DDL)
(1)创建表(核心)
① 创建管理表
sql
CREATE TABLE IF NOT EXISTS student (
id INT COMMENT '学生ID',
name STRING COMMENT '学生姓名',
age INT COMMENT '学生年龄',
score DOUBLE COMMENT '学生分数'
)
COMMENT '学生表(管理表)'
-- 指定字段分隔符
FIELDS TERMINATED BY ','
-- 指定行分隔符(默认\n,可省略)
LINES TERMINATED BY '\n'
-- 存储格式(默认TEXTFILE,可省略)
STORED AS TEXTFILE;
-- 若不指定LOCATION,默认路径:/user/hive/warehouse/db_name.db/student
② 创建外部表
sql
CREATE EXTERNAL TABLE IF NOT EXISTS log_table (
log_time TIMESTAMP COMMENT '日志时间',
user_id STRING COMMENT '用户ID',
action STRING COMMENT '用户操作',
ip STRING COMMENT 'IP地址'
)
COMMENT '日志表(外部表)'
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
-- 关键:指定外部表数据的HDFS路径
LOCATION '/user/log/data'
STORED AS TEXTFILE;
③ 创建分区表
sql
-- 单分区表(按日期分区)
CREATE EXTERNAL TABLE IF NOT EXISTS log_partition (
log_time TIMESTAMP,
user_id STRING,
action STRING,
ip STRING
)
COMMENT '日志分区表'
PARTITIONED BY (day STRING COMMENT '分区字段:日期,格式yyyy-MM-dd')
FIELDS TERMINATED BY '\t'
LOCATION '/user/log/partition_data';
-- 多级分区表(按日期+小时分区)
CREATE EXTERNAL TABLE IF NOT EXISTS log_multi_partition (
log_time TIMESTAMP,
user_id STRING,
action STRING,
ip STRING
)
PARTITIONED BY (day STRING, hour INT)
FIELDS TERMINATED BY '\t'
LOCATION '/user/log/multi_partition_data';
④ 创建分桶表
sql
-- 开启分桶功能(临时生效,退出Hive后失效)
set hive.enforce.bucketing=true;
CREATE TABLE IF NOT EXISTS user_bucket (
user_id STRING,
name STRING,
age INT,
gender STRING
)
COMMENT '用户分桶表'
-- 按user_id分桶,分8个桶
CLUSTERED BY (user_id) INTO 8 BUCKETS
-- 可选:按gender排序(分桶内排序,优化查询)
SORTED BY (gender ASC)
STORED AS TEXTFILE;
⑤ 复制表(仅复制表结构,不复制数据)
sql
-- 方式1:复制表结构(包括注释、分隔符等)
CREATE TABLE IF NOT EXISTS student_copy LIKE student;
-- 方式2:通过查询复制表结构(可修改字段)
CREATE TABLE IF NOT EXISTS student_copy2 AS
SELECT id, name, age FROM student WHERE 1=0; -- WHERE 1=0 不返回数据,仅复制结构
(2)查看表
sql
-- 查看当前数据库下所有表
SHOW TABLES;
-- 查看表结构
DESCRIBE student;
-- 查看表结构详情(包括分区、存储格式、路径等)
DESCRIBE EXTENDED student;
-- 查看分区表的分区信息
SHOW PARTITIONS log_partition;
(3)修改表
sql
-- 1. 修改表名
ALTER TABLE student RENAME TO student_new;
-- 2. 修改表注释
ALTER TABLE student_new SET COMMENT '修改后的学生表';
-- 3. 添加字段
ALTER TABLE student_new ADD COLUMNS (address STRING COMMENT '家庭地址');
-- 4. 修改字段(名称/类型/注释)
ALTER TABLE student_new CHANGE COLUMN address addr STRING COMMENT '居住地址';
-- 5. 删除字段(Hive 2.0+支持)
ALTER TABLE student_new REPLACE COLUMNS (
id INT COMMENT '学生ID',
name STRING COMMENT '学生姓名',
age INT COMMENT '学生年龄'
); -- 保留指定字段,删除其他字段
-- 6. 添加分区(分区表专用)
ALTER TABLE log_partition ADD IF NOT EXISTS
PARTITION (day='2024-01-01')
PARTITION (day='2024-01-02');
-- 7. 删除分区(分区表专用)
ALTER TABLE log_partition DROP IF EXISTS PARTITION (day='2024-01-01');
(4)删除表
sql
DROP TABLE IF EXISTS student_new;
4.3 数据操作(DML)
(1)加载数据(LOAD DATA)
核心:将本地文件或HDFS文件加载到Hive表中,本质是移动/复制文件(不是导入,不改变文件内容)。
sql
-- 1. 从本地文件加载(COPY,本地文件仍保留)
LOAD DATA LOCAL INPATH '/root/data/student.txt'
INTO TABLE student
-- 可选:覆盖表中现有数据(默认是追加)
OVERWRITE;
-- 2. 从HDFS文件加载(MOVE,HDFS原文件会被删除)
LOAD DATA INPATH '/user/data/student.txt'
INTO TABLE student
OVERWRITE;
-- 3. 加载数据到指定分区(分区表专用)
LOAD DATA LOCAL INPATH '/root/data/log_20240101.txt'
INTO TABLE log_partition
PARTITION (day='2024-01-01');
(2)插入数据(INSERT)
适用于分桶表、动态分区,或从其他表查询数据插入当前表。
sql
-- 1. 插入单条数据(不推荐,效率低)
INSERT INTO TABLE student VALUES (1, '张三', 18, 90.5);
-- 2. 从其他表查询插入(常用)
-- 追加插入
INSERT INTO TABLE student_copy
SELECT id, name, age, score FROM student WHERE age > 18;
-- 覆盖插入
INSERT OVERWRITE TABLE student_copy
SELECT id, name, age, score FROM student WHERE age <= 18;
-- 3. 插入到多个表(一次查询,插入多个表,效率高)
FROM student
INSERT OVERWRITE TABLE student_18 SELECT id, name WHERE age = 18
INSERT OVERWRITE TABLE student_19 SELECT id, name WHERE age = 19;
-- 4. 分桶表插入(必须用INSERT,不能用LOAD)
INSERT OVERWRITE TABLE user_bucket
SELECT user_id, name, age, gender FROM user_table;
(3)动态分区插入(分区表核心技巧)
无需手动指定分区值,根据查询结果自动匹配分区字段,适合大批量分区插入。
sql
-- 开启动态分区(临时生效)
set hive.exec.dynamic.partition=true;
-- 允许全动态分区(不指定静态分区,所有分区都是动态的)
set hive.exec.dynamic.partition.mode=nonstrict;
-- 动态分区插入(按day字段动态分区)
INSERT OVERWRITE TABLE log_partition
PARTITION (day) -- 不指定分区值,动态匹配
SELECT log_time, user_id, action, ip, substr(log_time, 1, 10) AS day FROM log_raw;
-- 说明:substr(log_time, 1, 10) 提取日期(yyyy-MM-dd),作为分区值
(4)删除数据(DELETE)
Hive默认不支持DELETE(非事务表),Hive 3.0+支持事务表删除,需开启事务配置,一般不推荐(效率低)。
sql
-- 仅事务表可用
DELETE FROM student WHERE id = 1;
4.4 查询操作(DQL)
Hive SQL查询语法与MySQL基本一致,重点掌握Hive专属优化(分区裁剪、分桶连接、函数)。
(1)基础查询
sql
-- 简单查询
SELECT id, name, age FROM student;
-- 去重查询
SELECT DISTINCT gender FROM student;
-- 条件查询(WHERE)
SELECT * FROM student WHERE age > 18 AND score > 80;
-- 排序查询(ORDER BY:全局排序,仅一个Reduce,效率低)
SELECT * FROM student ORDER BY score DESC;
-- 局部排序(SORT BY:每个Reduce内部排序,效率高,需配合DISTRIBUTE BY)
SELECT * FROM student DISTRIBUTE BY gender SORT BY score DESC;
-- 分组查询(GROUP BY)
SELECT gender, AVG(score) AS avg_score FROM student GROUP BY gender;
-- 分组过滤(HAVING,过滤分组后的结果,不能用WHERE)
SELECT gender, AVG(score) AS avg_score
FROM student
GROUP BY gender
HAVING avg_score > 85;
(2)Join查询(重点,优化核心)
Hive支持内连接、左连接、右连接、全连接,重点优化:小表在前,开启Map Join(自动将小表加载到内存,避免Reduce阶段 shuffle)。
sql
-- 开启Map Join(临时生效,Hive 0.11+默认自动开启)
set hive.auto.convert.join=true;
-- 1. 内连接(只保留两边都匹配的数据)
SELECT s.id, s.name, c.course_name
FROM student s
INNER JOIN course c
ON s.course_id = c.id;
-- 2. 左连接(保留左表所有数据,右表匹配不到显示NULL)
SELECT s.id, s.name, c.course_name
FROM student s
LEFT JOIN course c
ON s.course_id = c.id;
-- 3. 右连接(保留右表所有数据,左表匹配不到显示NULL)
SELECT s.id, s.name, c.course_name
FROM student s
RIGHT JOIN course c
ON s.course_id = c.id;
-- 4. 全连接(保留左右表所有数据,匹配不到显示NULL)
SELECT s.id, s.name, c.course_name
FROM student s
FULL JOIN course c
ON s.course_id = c.id;
-- 5. 分桶连接(分桶表专用,优化Join效率)
SELECT u.name, o.order_id
FROM user_bucket u
JOIN order_bucket o
ON u.user_id = o.user_id;
-- 6. 笛卡尔积(慎用,效率极低,无ON条件)
SELECT s.name, c.course_name FROM student s, course c;
(3)分区裁剪(查询优化重点)
查询分区表时,必须指定分区字段,避免全表扫描,大幅提升查询效率。
sql
-- 坏示例:全表扫描(扫描所有分区,效率低)
SELECT * FROM log_partition WHERE action = 'login';
-- 好示例:分区裁剪(仅扫描day=2024-01-01的分区)
SELECT * FROM log_partition WHERE day = '2024-01-01' AND action = 'login';
-- 多分区裁剪(多级分区)
SELECT * FROM log_multi_partition WHERE day = '2024-01-01' AND hour = 8;
4.5 常用函数(重点掌握)
(1)字符串函数
sql
-- 1. 字符串长度
SELECT length(name) FROM student;
-- 2. 字符串截取(substr(字符串, 起始索引, 长度),索引从1开始)
SELECT substr(log_time, 1, 10) AS day FROM log_table; -- 提取日期
-- 3. 字符串拼接(concat,多个字符串用逗号分隔)
SELECT concat(name, '-', gender) AS name_gender FROM student;
-- 4. 字符串替换
SELECT regexp_replace(ip, '192.168.', 'xxx.xxx.') FROM log_table;
-- 5. 字符串分割(split,返回数组)
SELECT split(name, '_')[0] AS first_name FROM student; -- 按下划线分割,取第一个元素
(2)日期函数
sql
-- 1. 获取当前日期(yyyy-MM-dd)
SELECT current_date();
-- 2. 获取当前时间戳(yyyy-MM-dd HH:mm:ss)
SELECT current_timestamp();
-- 3. 日期转字符串(date_format)
SELECT date_format(log_time, 'yyyy-MM-dd') AS day FROM log_table;
-- 4. 字符串转日期(to_date)
SELECT to_date('2024-01-01', 'yyyy-MM-dd') AS date FROM student;
-- 5. 日期加减(date_add/date_sub)
SELECT date_add(current_date(), 7) AS next_week; -- 当前日期加7天
SELECT date_sub(current_date(), 1) AS yesterday; -- 当前日期减1天
-- 6. 计算两个日期差值(datediff,结束日期-开始日期)
SELECT datediff('2024-01-10', '2024-01-01') AS diff_days;
(3)聚合函数
sql
-- 求和
SELECT sum(score) AS total_score FROM student;
-- 平均值
SELECT avg(score) AS avg_score FROM student;
-- 最大值/最小值
SELECT max(score) AS max_score, min(score) AS min_score FROM student;
-- 计数(count(*) 计数所有行,count(字段) 计数非NULL行)
SELECT count(*) AS total_num, count(name) AS name_num FROM student;
-- 去重计数
SELECT count(DISTINCT gender) AS gender_num FROM student;
(4)复杂类型函数
sql
-- 1. ARRAY函数(size:数组长度;array_contains:判断是否包含元素)
SELECT size(score_array) AS score_count FROM student;
SELECT array_contains(score_array, 100) AS has_full_score FROM student;
-- 2. MAP函数(map_keys:获取所有键;map_values:获取所有值)
SELECT map_keys(info_map) AS keys FROM student;
SELECT map_values(info_map) AS values FROM student;
-- 3. STRUCT函数(直接通过.访问字段,无需函数)
SELECT info.name, info.age FROM student;
(5)条件函数
sql
-- 1. CASE WHEN(多条件判断)
SELECT
name,
score,
CASE
WHEN score >= 90 THEN '优秀'
WHEN score >= 80 THEN '良好'
WHEN score >= 60 THEN '及格'
ELSE '不及格'
END AS grade
FROM student;
-- 2. IF函数(简单条件判断,IF(条件, 满足返回值, 不满足返回值))
SELECT name, IF(score >= 60, '及格', '不及格') AS pass_status FROM student;
五、Hive优化技巧(必掌握)
5.1 分区优化
-
核心:查询时必须指定分区字段,避免全表扫描(分区裁剪)。
-
合理选择分区字段:选择查询频率高、基数适中的字段(如日期、地区),避免分区过多(如按秒分区,导致目录爆炸)。
-
使用动态分区插入大批量分区数据,避免手动添加分区。
5.2 Join优化
-
小表在前,大表在后:Hive会自动将小表加载到内存(Map Join),减少Reduce阶段 shuffle。
-
开启自动Map Join:set hive.auto.convert.join=true(默认开启),小表阈值可配置(hive.mapjoin.smalltable.filesize,默认256M)。
-
分桶表Join:两个表按相同字段分桶,Join时仅需关联对应桶的数据,大幅减少数据传输。
-
避免笛卡尔积:禁止无ON条件的Join,效率极低。
5.3 数据存储优化
-
选择合适的存储格式:
-
TEXTFILE:默认格式,可读性强,压缩率低,适合测试。
-
ORC:优化行列存储,压缩率高、查询快,适合生产环境(推荐)。
-
PARQUET:列式存储,适合多字段查询、大表存储,与Spark兼容性好。
-
-
开启数据压缩:减少HDFS存储占用和网络传输量,常用压缩格式:Snappy(压缩/解压快)、Gzip(压缩率高,解压慢)。
-
合理分桶:分桶数量建议等于或小于Reduce数量,避免数据倾斜。
5.4 任务参数优化
-
调整Reduce数量:根据数据量调整,避免Reduce过多(任务碎片化)或过少(单个任务压力大)。
-
手动设置:set mapreduce.job.reduces=5;
-
自动调整:Hive会根据数据量自动计算Reduce数量(默认)。
-
-
开启并行执行:set hive.exec.parallel=true,允许同时执行多个MapReduce任务(适合多表Join、多分区插入)。
-
避免小文件过多:小文件会导致Map任务过多,可通过合并小文件解决:
-
输入合并:set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
-
输出合并:set hive.merge.mapfiles=true(Map端合并)、set hive.merge.mapredfiles=true(Reduce端合并)。
-
5.5 数据倾斜优化
数据倾斜:某一个/几个Reduce任务处理的数据量远超其他任务,导致任务执行缓慢、超时。
(1)常见原因
-
Join时,某一个Key的值过多(如NULL值、热门值)。
-
Group By时,某一个分组的数据量过大。
(2)解决方案
-
NULL值处理:将NULL值替换为随机值(如concat('null_', rand())),分散到不同Reduce。
-
热门Key处理:将热门Key单独处理(过滤出来单独Join,再合并结果)。
-
开启负载均衡:set hive.optimize.skewjoin=true,自动检测倾斜Key,将倾斜数据分散到多个Reduce。
-
调整倾斜阈值:set hive.skewjoin.key=100000(默认,当某Key的行数超过该值,视为倾斜)。
六、Hive常见问题与解决方案
6.1 启动Hive CLI报错:Could not open client transport with JDBC Uri
-
原因:HiveServer2未启动,或端口被占用。
-
解决方案:启动HiveServer2(nohup hiveserver2 &),等待1-2分钟再连接;或检查10000端口是否被占用(netstat -tunlp | grep 10000),杀死占用进程。
6.2 元数据丢失,表无法查询
-
原因:MySQL数据库(元数据存储)崩溃、数据被删除;或元数据初始化失败。
-
解决方案:恢复MySQL备份的元数据;重新初始化元数据(注意:会删除现有元数据,谨慎操作)。
6.3 加载数据后,查询不到数据
-
原因1:数据分隔符不匹配(如表指定逗号分隔,数据实际是制表符分隔)。
-
解决方案1:重新创建表,指定正确的分隔符;或修改数据分隔符。
-
原因2:分区表加载数据后,未添加分区(Hive元数据中没有分区信息)。
-
解决方案2:执行ALTER TABLE 表名 ADD PARTITION(...),或修复分区(MSCK REPAIR TABLE 表名;)。
-
原因3:数据路径错误(外部表指定的LOCATION路径与实际数据路径不一致)。
-
解决方案3:修改表的LOCATION路径,或移动数据到指定路径。
6.4 查询效率极低,一直卡在Map/Reduce阶段
-
原因1:未做分区裁剪,全表扫描大表。
-
解决方案1:查询时添加分区条件,开启分区裁剪。
-
原因2:数据倾斜,某Reduce任务数据量过大。
-
解决方案2:参考"数据倾斜优化",处理倾斜Key。
-
原因3:小文件过多,Map任务数量过大。
-
解决方案3:开启小文件合并,或手动合并HDFS上的小文件。
6.5 分桶表插入数据后,查询不到数据
-
原因:分桶表必须用INSERT语句插入数据,不能用LOAD DATA;或未开启分桶功能。
-
解决方案:开启分桶功能(set hive.enforce.bucketing=true),用INSERT OVERWRITE插入数据。