load data local inpath '/data/dept.txt' into table dept_partitions partition(month='2020-01');
你写的这个语句:
在 Hive 里执行后,会发生这样的事情:
-
LOAD DATA不做数据过滤
它不会去解析dept.txt的内容,也不会只把“月份=2020-01”的数据挑出来。
Hive 只是把这个本地文件原封不动地拷贝(LOCAL表示从本地文件系统复制)到分区对应的 HDFS 目录。 -
数据直接进入对应的分区目录
Hive 会把/data/dept.txt文件复制到:/user/hive/warehouse/dept_partitions/month=2020-01/目录下(具体路径取决于你的
hive.metastore.warehouse.dir配置)。
文件名可能还是dept.txt,也可能会改成 Hive 自动生成的名字(比如000000_0),但内容就是你本地文件的全部内容。 -
文件内容不一定匹配分区值
Hive 不会检查文件里的数据列是否真的都是 2020-01。分区值完全由你在PARTITION (month='2020-01')指定的参数决定,查询时 Hive 会用这个分区值来当做一列返回(即使文件里的数据和它不一致)。
结论
执行完这个 LOAD DATA LOCAL ... PARTITION ... 语句后,
HDFS month=2020-01 目录下放的就是整个 dept.txt 文件的全部数据,Hive 并不会只保留 month=2020-01 的行。
如果你想让分区目录里只包含符合分区条件的数据,就得先用 INSERT OVERWRITE ... SELECT ... WHERE month='2020-01' 这种方式去筛选。
You said:
ChatGPT said:
对的 ✅。
你第二次执行
Hive 会再次原封不动地把本地 /data/dept.txt 文件复制到分区目录:
和第一次一样:
-
不会检查文件里的
month列值是否是 2020-02; -
不会做去重或过滤;
-
只是把整个文件搬到新的分区目录。
所以最终 HDFS 上会出现两份一模一样的 dept.txt(或者 Hive 给它改的内部文件名):
.../dept_partitions/month=2020-01/000000_0
.../dept_partitions/month=2020-02/000000_0
内容完全相同,只是分区路径不同。
如果你想避免这种“数据内容和分区值可能不一致”的情况,就得先把文件导入临时表,再用 INSERT OVERWRITE ... SELECT ... WHERE ... 去按分区值写入。
You said:
ChatGPT said:
是的,从存储利用率的角度看,这确实可能造成大量重复文件,看起来有点“不合理”,但 Hive 这么设计是有历史和技术背景的。
我给你拆开解释一下:
1. Hive 的 LOAD DATA 设计初衷
-
LOAD DATA在 Hive 中本质上只是一个 文件搬运操作(move或copy),不是数据导入+转换。 -
它的目标是快速让数据可查询,而不是保证数据内容和分区字段一致。
-
因为它最早就是给“用户自己已经准备好分区目录+数据”的场景用的。
例如:/warehouse/sales/year=2024/month=01/ <--- 已经是1月的数据/warehouse/sales/year=2024/month=02/ <--- 已经是2月的数据Hive 只负责登记元数据,不去动内容。
2. 为什么会造成重复文件
-
你如果多次
LOAD DATA同一个原始文件到不同分区目录,Hive 并不会检查文件内容,只会简单地复制或移动。 -
HDFS 不像数据库那样有“行存储”和“索引指针”,它没有“去重存储”的机制(除非额外用 HDFS 层的硬链接或 dedup 工具)。
-
结果就是不同分区目录下可能会放同一份内容的多个拷贝。
3. 为什么 Hive 没做自动过滤
-
过滤意味着 Hive 必须解析文件,读取每一行,然后判断分区列是否匹配,这个过程就是一次
MapReduce或Tez/Spark任务。 -
这样性能会比
LOAD DATA慢很多,失去了快速导入的优势。 -
因此 Hive 设计了另一种方式:用
INSERT OVERWRITE ... SELECT ... WHERE来做筛选,而不是在LOAD DATA里搞。
4. 合理的做法
如果你不想在 HDFS 产生大量重复文件,可以用下面的流程:
-
先把数据用
LOAD DATA或 HDFSput放到一个“原始数据表”里(非分区)。 -
再用
INSERT OVERWRITE TABLE ... PARTITION(...) SELECT ...过滤并写入目标分区表。
这样每条数据只存一份,分区目录里的内容和分区值保持一致。
总结
-
Hive 的
LOAD DATA更像是“注册文件到表”而不是“智能导入”。 -
直接多次
LOAD同一个文件到不同分区,HDFS 就会存多份。 -
如果追求存储合理性,要自己先过滤再写分区。
我可以帮你画一张 Hive 数据加载三种模式对比图(LOAD / INSERT / 外部分区),这样你以后就一眼能看出什么情况下会重复存储,什么情况下不会。
你要我画吗?
You said:
ChatGPT said:
好,那我帮你画一个 Hive 数据加载三种模式对比图,让你清楚看到什么时候会产生重复文件,什么时候不会。
Hive 数据加载模式对比
| 加载方式 | 过程 | 是否产生重复文件 | 场景适用 |
|---|---|---|---|
| ① LOAD DATA LOCAL/INPATH | 直接把文件 移动/复制 到分区或表目录,不解析内容 | ✅ 可能(多次LOAD同一文件到不同分区就会多份) | 已经提前按分区准备好数据的场景 |
| ② INSERT OVERWRITE/INTO | 读取数据 → 运行SQL过滤/转换 → 写入目标分区文件 | ❌ 不会重复(只保留符合条件的数据) | 数据需要按分区字段筛选、去重、转换的场景 |
| ③ 外部分区表 (External Table) + ALTER ADD PARTITION | 数据文件已在HDFS固定目录,Hive只登记元数据,不复制文件 | ❌ 不会重复(文件只存一份) | 已经有HDFS现成分区目录的场景 |
流程图
(本地/HDFS原始文件)
│
┌────────┼──────────┐
│ │ │
LOAD DATA INSERT 外部分区表+ADD PARTITION
│ │ │
[文件直接搬] [解析/过滤] [只登记元数据]
│ │ │
文件直接出现在 分区目录 目录已存在
分区目录下 仅符合条件的数据
│ │
可能有重复 无重复
存储策略建议
-
不想重复存储 → 先放到“原始表”里,再
INSERT OVERWRITE按分区字段写入目标表。 -
要快速加载 → 直接
LOAD DATA,但前提是你确信文件本身已按分区切好。 -
已经有分区目录 → 建立外部分区表,
ALTER TABLE ... ADD PARTITION,不搬文件。
🛠 Hive 分区加载最佳实践流程
【数据来源】
┌───────────────┐
│ 本地/外部系统 │
│ dept.txt │
└───────┬───────┘
│
▼
【HDFS 原始数据区】
/data/raw/dept/dept.txt (非分区原始表)
│
▼
┌───────────────────────────┐
│ Step 1: 建立临时原始表 │
│ CREATE TABLE dept_raw │
│ (...字段...) │
│ ROW FORMAT ... │
│ STORED AS ... │
│ LOCATION '/data/raw/dept'│
└───────────┬───────────────┘
│ (LOAD DATA一次即可)
▼
┌───────────────────────────┐
│ Step 2: 目标分区表 │
│ CREATE TABLE dept_partitions│
│ (...字段...) │
│ PARTITIONED BY (month STRING)│
│ STORED AS ... │
└───────────┬────────────────┘
│
▼
┌───────────────────────────┐
│ Step 3: 按分区字段写入 │
│ INSERT OVERWRITE TABLE │
│ dept_partitions │
│ PARTITION(month) │
│ SELECT col1, col2, ..., │
│ month │
│ FROM dept_raw; │
└───────────────────────────┘
📌 核心原则
-
一次 LOAD,多次分区写入
-
所有原始文件只加载一次到非分区表(避免多份重复文件)。
-
-
分区值由 SQL 决定
-
由
SELECT中的字段值自动生成分区,保证分区字段和数据一致。
-
-
按需更新分区
-
新数据来时,只
INSERT OVERWRITE目标分区,不影响其他分区。
-
🎯 优势
-
无重复文件:HDFS 中同一份数据只存一份。
-
分区字段和数据强一致:不会出现 month=2020-01 目录里有 2020-02 的行。
-
可维护性强:分区更新可独立执行,不影响全表。
那总结一下今天的结论:
-
LOAD DATA在 Hive 里只是搬文件,不会过滤数据,容易造成同一份文件多份存储。 -
避免重复 最稳妥的做法是:先放到非分区原始表,再用
INSERT OVERWRITE按分区字段写入目标表。 -
外部分区表 适合已有分区目录的场景,Hive 只登记元数据,不会多存文件。
这样你以后在 Hive 里加载分区数据时,就能既节省 HDFS 空间,又保持数据和分区一致了。

浙公网安备 33010602011771号