Hive:DML 数据操作------Load、Insert、Export、Import 四种数据进出方式
Hive数据进出有四种方式:LOAD DATA(本地复制、HDFS剪切)用于批量加载文件;INSERT SELECT实现表间结果集迁移,支持追加或覆盖;INSERT VALUES可手动插入单行,但生产慎用;INSERT DIRECTORY将查询结果导出至本地或HDFS文件系统;EXPORT/IMPORT则支持整表连同元数据的跨集群迁移。其中,LOAD最高效,INSERT适用于加工逻辑,EXPORT/IMPORT适合表级迁移。核心原则:能用LOAD就不用INSERT,数据操作以文件和批量为主。
目录
- 一、先想清楚:为什么 Hive 灌数据和 MySQL 不一样
- 二、方式一:LOAD DATA 加载文件(最常用)
- 三、方式二:INSERT 把查询结果插入表
- 四、方式三:INSERT VALUES 直接插值
- 五、方式四:查询结果导出到文件系统
- 六、EXPORT / IMPORT:带元数据的导入导出
- 七、四种方式对比总结
一、先想清楚:为什么 Hive 灌数据和 MySQL 不一样
在 MySQL 里你习惯了随时 insert into ... values(...) 单条插、update 单条改。到 Hive 里请先换个思维:
Hive 是面向批量分析的数仓工具,不是事务数据库。 数据进出的主角是"文件"和"批量结果集",而不是"单行记录"。
所以 Hive 的 DML 围绕四个问题展开:
- 本地/集群的文件怎么整批装进表?→ LOAD DATA
- 一张表的查询结果怎么存进另一张表?→ INSERT SELECT
- 表里的数据怎么导出成文件?→ INSERT DIRECTORY / EXPORT
- 整张表连结构带数据怎么搬家?→ EXPORT / IMPORT
下面逐一实操。统一使用 students 表:
sql
create table if not exists bigdata.students1(
id string comment '学号',
name string comment '姓名',
age int comment '年龄',
sex string comment '性别',
clazz string comment '班级'
)
row format delimited fields terminated by ',';
二、方式一:LOAD DATA 加载文件(最常用)
2.1 语法
sql
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename
[PARTITION (partcol1=val1, ...)]
三个可选零件,每个都是考点:
| 零件 | 不写 / 写了 的区别 |
|---|---|
| LOCAL | 写 :从 Linux 本地路径加载;不写:从 HDFS 路径加载 |
| OVERWRITE | 写 :清空表里原有数据再装;不写:追加到表尾 |
| PARTITION | 分区表指定装到哪个分区(第 4 篇展开) |
2.2 加载本地文件:复制
sql
load data local inpath '/root/sh_code/student.csv' overwrite into table students1;
查询验证:
sql
select * from students1 limit 3;
输出:
OK
id name age sex clazz
1500100001 施笑槐 22 男 理科一班
1500100002 吕梓杨 24 男 理科二班
1500100003 张三 21 女 理科一班
Time taken: 2.104 seconds, Fetched: 3 row(s)
本质:把本地文件复制一份到表的 HDFS 目录下。 本地原文件还在。
2.3 加载 HDFS 文件:剪切!
先准备一张同结构的空表,把文件先传到 HDFS:
shell
hdfs dfs -put student.csv /student.csv
sql
create table if not exists bigdata.students2 like students1;
load data inpath '/student.csv' overwrite into table students2;
再查一下 HDFS 根目录:
shell
hdfs dfs -ls /
Found 3 items
-rw-r--r-- ... /students5 (其他文件)
drwxr-xr-x ... /data
# /student.csv 不见了!它被"移动"进了 students2 的表目录
核心区别(面试可考):
| 来源 | 行为 | 原文件 |
|---|---|---|
load data local |
复制到表目录 | 还在 |
load data (hdfs) |
移动到表目录 | 消失(相当于 mv) |
口诀:本地复制,HDFS 剪切。 道理很简单:数据都已经在 HDFS 上了,再复制一份纯属浪费存储,挪个目录就完事。
2.4 OVERWRITE 追加实验
不加 OVERWRITE 就是追加。连续执行两次加载(去掉 overwrite):
sql
load data local inpath '/root/sh_code/student.csv' into table students1;
load data local inpath '/root/sh_code/student.csv' into table students1;
sql
select count(1) from students1;
OK
_c0
1000 (假设原文件1000行,现在翻倍了)
生产建议:写脚本重复执行时,先想清楚要"追加"还是"覆盖",用错 OVERWRITE 会把辛苦算好的数据清掉,用错追加会数据翻倍。
三、方式二:INSERT 把查询结果插入表
3.1 INSERT INTO vs INSERT OVERWRITE
sql
-- into:追加写入
insert into table students5 select * from students1;
-- overwrite:清空目标表再写入
insert OVERWRITE table students5 select * from students1;
典型场景:宽表加工。比如从学生明细表算出一张"每班人数汇总表":
sql
insert overwrite table clazz_count
select clazz, count(1) as num
from students1
group by clazz;
这个"查询结果落成一张新表"的模式,就是数仓分层(ODS → DWD → DWS)最基础的动作。
3.2 性能提醒
insert ... select 底层是一个 MapReduce 任务,比 load 慢得多。原则:能 load 不 insert;表到表的加工才用 insert。
四、方式三:INSERT VALUES 直接插值
sql
insert into table students5 VALUES('100001','张三',25,'1','文科一班');
能跑,但生产上基本不用:
- 插一条数据也要起一个 MR 任务,秒级变分钟级
- 数仓的数据来源是批量文件或上游表,不存在"手工逐行插"
了解即可,别养成习惯。
五、方式四:查询结果导出到文件系统
5.1 单路导出
sql
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
[ROW FORMAT row_format] [STORED AS file_format]
SELECT ... FROM ...;
案例:把表数据导出到 Linux 本地目录,逗号分隔:
sql
insert overwrite local directory '/root/students5'
row format delimited fields terminated by ','
select * from students5;
查看结果:
shell
cat /root/students5/000000_0 | head -3
1500100001,施笑槐,22,男,理科一班
1500100002,吕梓杨,24,男,理科二班
1500100003,张三,21,女,理科一班
几个细节:
- 不写
LOCAL就是导到 HDFS 目录 - 结果文件名固定形如
000000_0,有几个 Reduce 就有几个文件 row format ... terminated by ','决定导出文件的分隔符,不写默认是控制符\001,打开会全是乱码
5.2 多路导出(Multiple Inserts)
一次查询结果可以同时导到多个地方,语法是从 FROM 开头:
sql
FROM students5
INSERT OVERWRITE LOCAL DIRECTORY '/root/out_male'
SELECT * WHERE sex = '男'
INSERT OVERWRITE LOCAL DIRECTORY '/root/out_female'
SELECT * WHERE sex = '女';
一次扫描、多份输出,省了重复读表的开销。
六、EXPORT / IMPORT:带元数据的导入导出
前面四种方式只搬"数据",EXPORT/IMPORT 连元数据 (表结构等)一起打包,常用于集群间整表迁移。
6.1 导出
sql
EXPORT TABLE students5 TO '/students5';
6.2 导入
先把目标表清空(模拟"换个集群的空表"):
sql
truncate table students1;
import table students1 from '/students5';
验证:
sql
select count(1) from students1;
OK
_c0
1000
数据回来了。注意 EXPORT/IMPORT 走的是 HDFS 路径,迁移跨集群时通常配合 distcp 把导出目录拷到目标集群再 IMPORT。
七、四种方式对比总结
| 方式 | 方向 | 数据粒度 | 是否动元数据 | 典型场景 |
|---|---|---|---|---|
| LOAD DATA(local) | 文件 → 表 | 整个文件 | 否 | 灌原始数据,最快 |
| LOAD DATA(hdfs) | 文件 → 表 | 整个文件 | 否 | HDFS 上已有文件挂到表(剪切) |
| INSERT SELECT | 表 → 表 | 结果集 | 否 | 数仓分层加工 |
| INSERT VALUES | 手工 → 表 | 单行 | 否 | 测试玩玩,生产不用 |
| INSERT DIRECTORY | 表 → 文件 | 结果集 | 否 | 导出分析结果 |
| EXPORT / IMPORT | 表 ↔ HDFS 目录 | 整表 | 是(连结构) | 跨集群整表迁移 |
一句话收尾 :日常数据处理 90% 只用两个动作------load 灌数、insert ... select 加工;剩下四个了解即可,面试和救急时能想起来就行。