前言:

本文基于数学与大数据学院2024级数据科学与大数据技术专业课程《分布式数据库原理及技术》。该课程考核难度较大,需特别用心认真听课!我将个人笔记开源,旨在为后续的新同学提供复习参考,欢迎交流与讨论(虽然我也可能忘记了((

Chiale

2026.8.1

资料下载: https://pan.baidu.com/s/1k6hAS7tVlPAeOwbevS7b7A?pwd=t2uv 提取码: t2uv

第一篇 概论与基础

第一章 分布式数据库概述

1.1 前沿技术科普

以下技术作为通识了解即可,构成本课程的学习背景:

技术理解
数据中台把企业内分散的数据资产汇聚、加工、服务化,向业务统一供给
数据湖仓(Lakehouse)同时具备数据湖的灵活存储与数据仓库的事务/Schema 能力
数据脱敏对敏感字段(如身份证、手机号)做变形或替换以保护隐私
分布式数据库的雏形(ICBC Bank)工商银行早期基于大型机的分布式账务系统
区块链多方参与的链式账本,依赖共识算法与不可篡改结构
TCP 三次握手四次挥手面向连接的传输层建连与断连流程
联邦学习 / 深度学习多方在不共享原始数据的前提下联合训练模型
结论:以上内容了解即可,作为科普知识看待,本课程重点在分布式数据库系统(Hive / Hadoop)。

1.2 分布式数据库与传统 RDBMS 的对比

Q1:传统的三级模式 / 两级映像在分布式数据库中是否改变?

A保留原有结构,但增加了新内容——引入了 全局模式(Global Schema)分片模式(Fragmentation Schema)

全局模式:从用户视角看,"整库"长什么样

分片模式:说明全局关系如何被切分到不同节点

原有"外模式 / 模式 / 内模式 + 映像"仍在,但被扩展以适配分布式存储

Q2:分布式数据库在存储/检索效率上通过何种指标与传统 RDBMS 进行对比?

A:两个核心指标——

存储空间大小:分布式能否减少单点膨胀

检索效率:是否仍能满足查询延迟与吞吐

Q3:HDFS(GFS)在存储体系上如何实现共享服务?

课堂问答留作思考。补充资料:02 Hadoop与HIve.pptx0 hdfs shell操作.txt

Q4:HIVE 的三种部署方式及使用环境

部署方式metastore 存储适用场景
内嵌模式(Derby)嵌入式 Derby 数据库单人本地调试;只允许一个会话
本地模式(Local)MySQL/PostgreSQL 等独立 RDBMS单人开发 / 教学实验,HIVE 与 metastore 在同一进程
远程模式(Remote)独立的 MySQL 服务多客户端并发访问同一 metastore,生产环境

数据库系统的三级模式结构

图中标注:内模式对应"存储",模式对应"放表的",外模式对应"逻辑独立";映像体现了 create view as select ... 的位置——逻辑独立、存储独立。

1.3 数据分类

类型典型代表处理方式
结构化MySQL、Oracle、关系表传统 SQL 数据库
半结构化JSON、XML可用 Hive JSON SerDe、Spark 解析
非结构化视频、图片YOLO 等模型识别 → 输出 JSON/CSV → 落入数据库

第二章 Hadoop 与 HIVE 体系结构

2.1 HDFS(GFS)存储体系

HDFS(Hadoop Distributed File System):源自 Google GFS 论文

核心特性:分块存储、多副本容错、一次写多次读

默认存储路径/warehousedir/home/xxx.db/表名/(Hive on HDFS 默认行为)

2.2 HIVE 三种工作模式

模式metastore 位置是否允许多会话
Derby嵌入式(每个客户端独立)
本地(Local)同节点 MySQL/PG单客户端
远程(Remote)远程独立 MySQL

2.3 集群环境与启停流程

集群环境

角色IP用户
master192.168.5.134root / 123123
slave1192.168.5.135root / 123123
slave2192.168.5.136root / 123123
MySQL 安装在 slave2,HIVE 启用本地模式;统一数据库名 bigdata2024;本地数据目录 /data

集群启动流程

  1. 关闭防火墙(三台虚拟机)
systemctl stop firewalld
  1. 启动 Zookeeper(三台虚拟机)
cd $ZOOKEEPER_HOME
bin/zkServer.sh start
bin/zkServer.sh status   # 1 个 leader,2 个 follower
  1. 启动 Hadoop(master)
cd $HADOOP_HOME
sbin/start-all.sh

在三台机器上 jps 查看进程。

  1. 启动 HIVE(slave2 启动 MySQL,slave1 或 master 启动 HIVE)
# slave2
systemctl start mysqld
# slave1 或 master
cd $HIVE_HOME
bin/hive

集群关闭流程(与启动对称):

  1. hive> quit;
  2. master:sbin/stop-all.sh
  3. 三台机器:cd $ZOOKEEPER_HOME && bin/zkServer.sh stop
  4. shutdown -h now

2.4 HIVE 基础配置与指令

配置分类

类别方式持久性
临时配置hive> set key=value;仅当前会话
永久配置修改 hive-site.xml持久化

常用配置(来自 执行命令集合.txt):

-- 在命令行中显示当前数据库名
set hive.cli.print.current.db=true;
-- 查询结果显示列名
set hive.cli.print.header=true;
-- 启用桶表
set hive.enforce.bucketing=true;
-- 压缩 HIVE 中间结果
set hive.exec.compress.intermediate=true;
-- 让 HIVE 尽量尝试 local 模式查询
set hive.exec.mode.local.auto=true;
-- 动态分区非严格模式
set hive.exec.dynamic.partition.mode=nonstrict;
-- ORC 表事务相关
set hive.support.concurrency=true;
set hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
set hive.compactor.initiator.on=true;
set hive.compactor.worker.threads=1;

最常用的元数据查询指令

-- 查看表字段
desc 表名;
-- 查看表详细信息(包括存储位置、参数)
desc formatted 表名;
-- 查看建表语句
show create table 表名;

关键知识点

  1. HIVE metastore 除 Derby 外采取文件夹存储管理——即 HIVE 表对应 HDFS 上的目录,而非文件。
  2. metastore 存储在 HDFS/warehousedir/home/xxx.db/表名(xxx 是数据库名)。

2.5 HDFS Shell 常用命令

# 目录与文件
hadoop fs -mkdir /usr
hadoop fs -touchz /emptyfile          # 创建空白文件
hadoop fs -ls /
hadoop fs -lsr /usr                   # 递归列出

# 大小统计
hadoop fs -du /usr                    # 各文件大小
hadoop fs -dus /usr                   # 汇总大小
hadoop fs -count /usr                 # 文件(夹)数量

# 移动 / 复制 / 删除
hadoop fs -mv /usr/opt/data/student.txt /usr
hadoop fs -cp /usr/opt/data/student.txt /usr
hadoop fs -rm /usr                    # 删除文件/空目录
hadoop fs -rm -r /dir                 # 递归删除

# 上传 / 下载 / 查看
hadoop fs -put /local/student.txt /hdfs/data   # 本地 → HDFS(本地原文件保留)
hadoop fs -get /hdfs/student.txt /local/data   # HDFS → 本地
hadoop fs -cat /student.txt
hadoop fs -text /student.txt

# 权限
hadoop fs -chmod 777 /emptyfile

# 思考:-put 后本地文件是否还有?-mv 呢?-cp 呢?
# -put:本地保留;-mv:本地删除;-cp:本地保留(HDFS 内复制)

第二篇 HIVE 数据管理

第三章 HIVE 数据类型与表创建

3.1 数据库管理

创建/查看/删除

-- 创建(指定存储位置)
create database owndb;
create database owndb location '/opt';

-- 查看
describe database owndb;
describe database extended owndb;
set hive.cli.print.current.db=true;   -- 在提示符显示当前 DB

-- 删除
drop database owndb;
drop database if exists owndb;
drop database if exists owndb cascade;   -- 级联删除库内所有表

-- 使用
use owndb;
show databases;
show databases in owndb;
默认存储路径/user/hive/warehouse/xxx.db/,通过 location 指定后自定义。

3.2 表的创建与存储位置

创建基本表(资料 1 HIVE指令实际操练1.txt2 表的创建与数据装载操作.txt):

create table customers(customerid int, firstname string, lastname string)
comment 'description of the table'
tblproperties('creator'='me', 'create-at'='2020-11-27 10:00')
location '/warehouse/home/customer'
stored as orcfile;

-- 仅复制表结构(不复制数据)
create table if not exists customer2 like owndb.customer;

查看表信息

desc customer;
desc extended customer;
desc formatted customer;
desc owndb.customer.lastname;     -- 查看某字段元数据

3.3 数据导入方式

create table 默认存储位置HDFS:/warehousedir/home/xxxx.db/表名(Directory)。

三种数据导入方式

方式命令示例HDFS 实际文件
INSERT 语句insert into ... select ...Directory/000000_0
HDFS puthadoop fs -put 本地文件 Directory直接落入指定目录
LOAD DATAload data local inpath '/data/st1.txt' into table student;Directory/xxx文件名

Q1(Lesson 4)create table xxx location 对整个命名有什么要求?

  • A:location 最好与默认文件管理体系一致,精确到表名级别;若含约束,location 必须放在最后一行
create table stu_test(sid int, sname string, sage int, addr string)
location '/testdb';
-- 结果:发现并没有 xxx.db/表名 这层目录,因为 location 是人为规定的。

load data 的两种形式

load data local inpath '/data/st1.txt' overwrite into table student;
-- 本地文件保留,不会被删除

load data inpath '/cloud/path' overwrite into table student;
-- 加载后会删除云端路径下的文件(HDFS 内移动)

3.4 基本数据类型与字段约束

-- 行/字段分隔符
row format delimited
fields terminated by ','         -- 字段分隔符
lines terminated by '\n'         -- 行分隔符
stored as textfile;              -- 存储格式

-- 首位字段字符串机制
create table stu_test(sid string, sname string, sage int, addr string)
row delimited fields terminated by ',' lines terminated by '\n' store as textfile;

3.5 复杂数据类型

3.5.1 Array(数组)

create table student1(sid int, sname string, grade array<float>)
row format delimited
fields terminated by ','
collection items terminated by '#'
lines terminated by '\n';

示例数据 student1.txt

1,zhangsan,80#90.5#35
2,lisi,90# #88
3,wangwu,87#87
4,mary, #60#
5,tom,60# #
6,jemy,78#

查询 sid=101 学生的第二个成绩(数组下标从 0 开始):

select grade[1] as second_grade
from student1
where sid = 101;

解析规则(# 之间的空值解析为 NULL)

sidsnamegrade(数组)说明
1zhangsan[80.0, 90.5, 35.0]3 个有效浮点数
2lisi[90.0, NULL, 88.0]中间 # 之间为空 → NULL
3wangwu[87.0, 87.0]2 个有效浮点数
4mary[NULL, 60.0, NULL]首尾 # 为空 → NULL
5tom[60.0, NULL, NULL]后两个 # 为空 → NULL数据仓库
6jemy[78.0]单个元素,结尾 # 忽略

装载

load data local inpath '/opt/data/student1.txt' into table student1;

3.5.2 Map(键值对)

create table student2(sid int, sname string, grade map<string, float>)
row format delimited
fields terminated by ','
collection items terminated by '#'
map keys terminated by ':'
lines terminated by '\n';

示例数据 student2.txt

1,zhangsan,语文:80#数学:90.5#英语:35
2,lisi,语文:90#数学:95#英语:88
3,wangwu,语文:87#数学:87#英语:56

查询 sid=101 学生的数学成绩

select grade['数学'] as math_score
from student3
where sid = 101;

示例数据

101,张三,数学:90.5#语文:88.0#英语:92.3
102,李四,数学:85.0#语文:90.2#英语:89.7
注意:若将 collection items terminated by '#' 删掉,则 Map 集合分割不存在,Map 只能有一个键值对。

装载

load data local inpath '/data/student2.txt' into table student2;

3.5.3 Struct(结构体)

create table student4(sid int, info struct<name:string, age:int, sex:string>)
row format delimited
fields terminated by ','
collection items terminated by '#'
lines terminated by '\n';

示例数据 student4.txt

1,name:zhangsan#age:19#sex:Female
2,name:lisi#age:20#sex:male
注意:Struct 不必写 map keys terminated by(教材中的写法是教学示意,标准 Struct 写法见上方)。

装载

load data local inpath '/opt/data/student4.txt' into table student4;

3.5.4 Array / Map / Struct 嵌套

Array 嵌套 Map(需要 JSON SerDe,普通 delimited 无法实现):

create table student3(sid int, sname string, grade array<map<string,float>>)
row format serde 'org.apache.hive.hcatalog.data.JsonSerDe';

load data local inpath '/opt/data/student3.txt' into table student3;

JSON 数据格式 student3.txt

{"sid":1,"sname":"zhangsan","grade":{"语文":80,"数学":90.5,"英语":35}}
{"sid":2,"sname":"lisi","grade":{"语文":80,"数学":90.5,"英语":35}}
{"sid":3,"sname":"wangwu","grade":{"语文":80,"数学":90.5,"英语":35}}

Map 嵌套 Array——同样无法实现

总结

Array、Map、Struct 不能嵌套使用(标准 delimited 模式下)

Array、Struct 属于 collection items

Map 若要实现多组数据并发,隐含包括了 collection items

想做嵌套 → 用 JSON SerDeORC 复杂类型


3.6 表的复制

方式命令复制结构复制数据
深拷贝create table student3_1_copy as select * from student3_1;
浅拷贝create table student3_2_copy like student3_1;

DW

图中数据仓库(DW)将数据复制到子分析模块,"如果结果正确"——深拷贝是数据也一并复制;浅拷贝仅复制表结构。

第四章 HIVE 存储模式

4.1 内部表与外部表

内部表 vs 外部表核心差异

维度内部表(Managed Table)外部表(External Table)
创建关键字create table ...create external table ...
DROP 表行为数据连同元数据一起删除仅删除元数据,location 数据保留
适用场景中间表、临时计算结果共享数据源、防止误删

外部表创建示例

create external table student_cp(sid int, sname string)
row format delimited fields terminated by ','
location "/tmpdb/student_cp";

DROP 外部表 → 位置 location 仍存在,仅引用切断;当下次仍有同名表(结构相同)时,仍会继续读取里面的数据。

原理:仅切断元数据对 location 的引用,存储位置仍存在。

查看表的位置

desc formatted tableName;
show create table test_table;

4.2 分区表

4.2.1 分区表的概念

分区表将数据按某个字段值分散到不同 HDFS 子目录,便于剪裁扫描。

常见误解:分区是数据行的字段?——分区字段是伪列,不参与业务字段存储,但出现在目录名里。

4.2.2 分区表创建与数据导入

静态分区

create table part_table(sid int, sname string, sage int)
partitioned by(addr string)
row format delimited fields terminated by ',';

load data local inpath '/home/student100'
into table part_table
partition(addr='guangxi');   -- 字符串,addr 必须写清楚,严格管控

装载后目录结构

/warehousedir/home/exam.db/part_table/addr=guangxi/student100
原数据未发生变化,分区字段是附加在路径上的伪列。

重复装载:存储位置 addr=xxx 不变,但子文件会多出 student100_copy_1

分区的增删

alter table part_table drop partition(addr='guangxi');   -- 删除该分区的子文件
alter table part_table add partition(addr='guangxi');    -- 新增分区
alter table part_table add partition(sage=20, addr='jiangsu');   -- 多分区需指定明确字段
注意show create table part_table; 的输出 不能用于新表的创建——它把 partitioned by 当字符串,不带分区值,无法直接复用。

4.2.3 多分区字段

create table part_table2(sid int, sname string)
partitioned by(sage int, addr string)
row format delimited fields terminated by ',';

load data local inpath '/home/student100'
into table part_table2
partition(sage=20, addr='guangxi');
注意alter table part_table add partition(sage=20, addr='jiangsu'); 需要同时指定两个明确分区的字段

4.2.4 分区的常见问题

问题答案
无分区表能否 add partition?新增分区字段是已有还是新增?不能;分区字段必须是建表时 partitioned by 中声明的伪列
已分区的表能否 add partition 新字段?不能直接 add 新分区字段;只能新增已有分区字段的值
非分区表能否变成(alter 成)分区表?不能
alter table ... add 操作本质是什么?虽然语法像 DDL 的 schema 操作,本质是对元数据的修改 + HDFS 目录的创建

错误示范

-- ❌ 非分区表不能 add 分区
create table student00(sid int, sname string);
alter table student00 add partition (gender string);   -- 报错

-- ❌ 这样也无法 load data
create table student00(sid int, sname string) partitioned by(data string);
load data local inpath '/data/x' into table student00;   -- 必须指定分区值

-- ✔ 正确
alter table student00 add partition (data = '20251011');

4.2.5 静态分区 vs 动态分区

维度静态分区动态分区
Schema相同相同
分区值指定装载时手动 partition(addr='xxx')由 SELECT 子句字段决定
数据控制精度精准(可配合 where 过滤)宽松(依赖源数据)
适用场景不干净数据、需要精准把控大量分区批量写入

动态分区装载(先创建含 partitioned by 的表,再 insert):

create table student3(sid int, sname string, grade map<string,float>)
partitioned by(addr string)
row format delimited
fields terminated by ',';

-- 静态 insert 也可指定具体分区
insert into table student3
partition (addr="anhui")
select * from ...;

4.2.6 经典实操:ah16 学生体检数据

重要:ah16 是贯穿多个 Lesson 的核心实操表,按要求不删除

普通表 ah16(资料:学生体检数据普通表和分区表导入.txt3 静态分区表的管理.txt):

create table ah16(
  sname string, sex int, minzu string, sge int, college string,
  major string, height int, weight int,
  breathlen float, breathweight int, physcore int,
  bloodtype string
)
row format delimited
fields terminated by ','
lines terminated by '\n'
stored as textfile;

load data local inpath '/data/16-1.csv' into table ah16;
-- Loading data to table bigdata20.ah16

ah16 的分区表 ah16_part(按血型分区):

create table ah16_part(
  sname string, sex int, minzu string, sge int, college string,
  major string, height int, weight int,
  breathlen float, breathweight int, physcore int
)
partitioned by (bloodtype string)
row format delimited
fields terminated by ','
lines terminated by '\n'
stored as textfile;

set mapreduce.job.reduces=4;

-- 按 bloodtype 分区装载
insert into ah16_part partition (bloodtype='A')
select sname, sex, minzu, sge, college, major, height, weight,
       breathlen, breathweight, physcore
from ah16 where bloodtype='A';

insert into ah16_part partition (bloodtype='B')
select sname, sex, minzu, sge, college, major, height, weight,
       breathlen, breathweight, physcore
from ah16 where bloodtype='B';

insert into ah16_part partition (bloodtype='AB')
select sname, sex, minzu, sge, college, major, height, weight,
       breathlen, breathweight, physcore
from ah16 where bloodtype='AB';

insert into ah16_part partition (bloodtype='O')
select sname, sex, minzu, sge, college, major, height, weight,
       breathlen, breathweight, physcore
from ah16 where bloodtype='O';

select count(*) from ah16_part;

4.3 桶表(Bucket Table)

4.3.1 桶表概念

  • :在表的数据存储层面,按某字段哈希分散到若干文件
  • 与分区的区别:分区按值目录切分;桶按哈希文件切分
  • 桶表三大问题(Lesson 9)

    1. 对应的 schema 创建方法
    2. 怎样将外部数据(CSV、跨 DB 表、insert 插入若干数据)导入到创建的表中
    3. select * 与 HDFS 文件查看指令 对应的数据

4.3.2 桶表创建(ah16 桶表实操)

跨 DB 引用 ah16

-- ah16 位于 owndb;当前在 bigdata24 库
-- 跨库语法
insert into table bucket_ah16
select * from owndb.ah16;

桶表创建

set hive.enforce.bucketing=true;
set mapreduce.job.reduces=4;

create table bucket_ah16(
  sname string, sex int, minzu string, sge int, college string,
  major string, height int, weight int,
  breathlen float, breathweight int, physcore int,
  bloodtype string
)
clustered by(sge) sorted by (sname desc) into 5 buckets
row format delimited
fields terminated by ',';

-- 跨 DB 装载
insert into table bucket_ah16
select * from owndb.ah16;

-- 分桶采样(Tablesample)
select * from bucket_ah16 tablesample(bucket 1 out of 5 on sge);

-- 查看建表语句(用于参考)
show create table bucket_ah16;

4.3.3 桶表的两个关键陷阱

buck.txt 数据

10,name10
1,name1
9,name9
3,name3
2,name2
8,name8
4,name4
12,name12
5,name5
15,name15
14,name14
38,name8
7,name7
11,name11

陷阱 1:使用 load data local 装载到桶表(4 桶),会形成四个桶,但 不会形成分区目录

create table buck_table(sid int, sname string)
clustered by(sid) sorted by(sname desc) into 4 buckets
row format delimited fields terminated by ',';

load data local inpath '/data/buck.txt' overwrite into buck_table;
select * from buck_table;                     -- 看不到分桶痕迹
hadoop fs -ls /warehousedir/home/bigdata24.db/buck_table   -- 没有分区目录

陷阱 2sorted by + load data 不会按姓名排序;只有通过 INSERT 语句插入数据时,每个桶内的数据才会按 sname 排序。

关键:仅定义 sorted by + load data 操作不会按姓名排序;只有通过 INSERT 语句插入数据时,每个桶内的数据才会按 sname 排序。

对比:load data 与 insert into 的差异

方式HDFS 是否分桶文件命名Tablesample 行为
load data ... into buck_table不形成分桶原始文件名仅逻辑分桶,标号从 1 开始
insert into buck_table select * from ...形成分桶00000_0(标号从 0 开始)物理分桶可采样
-- 用 insert 触发真正的分桶
insert into table buck_table select * from bigdata241.buck;

-- 采样(4 桶)
select * from buck_table tablesample(bucket 1 out of 4 on sid);

4.3.4 桶表的完整操作流程

set hive.enforce.bucketing=true;
set mapreduce.job.reduces=4;

-- 第一步:创建桶表
create table bucktable(sid int, sname string)
clustered by(sid) into 4 buckets
row format delimited fields terminated by ',' lines terminated by '\n';

create table bucktable2(sid int, sname string)
clustered by(sid) sorted by(sid desc) into 4 buckets
row format delimited fields terminated by ',' lines terminated by '\n';

-- 第三步:load data(不会触发分桶)
load data local inpath '/data/buck.txt' overwrite into table bucktable;
select * from bucktable;
hadoop fs -ls /datawarehouse/home/;

-- 第四步:建临时表(用于 insert 触发分桶)
create table tmptable(sid int, sname string)
row format delimited fields terminated by ',' lines terminated by '\n';

-- 第五步:load data 进临时表
load data local inpath '/data/buck.txt' overwrite into table tmptable;

-- 第六步:通过 insert 触发分桶
insert into bucktable select * from tmptable;
insert into bucktable2 select * from tmptable;

-- 第七步:查看桶内容
hadoop fs -cat /warehouse/home/owndb.db/bucktable2/000002_0
select * from bucktable2 tablesample(bucket 3 out of 4 on sid);
select * from bucktable  tablesample(bucket 3 out of 4 on sid);

4.4 四种表类型对比

类型数据管理方式关键语句
内部表(Table)数据与表结构绑定,drop 时级联删除create table t(...)
外部表(External Table)数据独立于表,drop 时仅删除元数据create external table t(...) location '...'
分区表(Partitioned Table)按分区字段值目录切分partitioned by(field type)
桶表(Bucket Table)按哈希分散到固定数量文件clustered by(x) into n buckets

核心问题(Lesson 8 Review):四张表的数据管理方式有什么不同?

内部表 ↔ 外部表:删除时是否级联处理存储位置

分区表:按字段值目录切分(便于剪裁)

桶表:按哈希文件切分(便于采样与高效 JOIN)


第三篇 HQL 数据操作

第五章 数据查询与连接

5.1 数据导出方式

导出到 HDFS

insert overwrite directory '/hdfs_path'
row format delimited
fields terminated by '#'
select * from xxx;

取回本地

hadoop fs -get /hdfs_path 本地路径

导出到基本表(实表)

create table xxx as select ... from ...;

导出到视图(虚表)

create view xx as select ... from ...;
select * from xx;   -- 触发 MR

清理 HDFS 目录

hadoop fs -rm -r /myin   # 里头有东西也能删除

5.2 JOIN 操作详解

实验表(来自 5 hive连接的案例设计.txt):

create table student100(sno int, sname string, sage int, saddr string)
row format delimited fields terminated by ',' lines terminated by '\n';

create table course100(cno int, cname string, ccredit int)
row format delimited fields terminated by ',' lines terminated by '\n';

create table SC100(sno int, cno int, grade int)
row format delimited fields terminated by ',' lines terminated by '\n';

实验数据

-- student100.txt
1,aa,17,anhui
2,bb,38,henan
3,cc,23,jiangsu
4,dd,56,beijing
5,ee,22,jiangsu
6,ff,23,shanghai
7,gg,24,fujian
8,hh,43,hubei
9,jj,25,jiangxi
10,kk,20,guangdong

-- course100.txt
1,java,3
2,c++,2
3,dephi,3
4,vc++,3
5,python,2
6,spark,2
7,hive,1

-- SC100.txt
1,2,98
2,1,90
5,4,67
10,7,56
8,6,78
5,12,78
6,15,76
20,6,89
30,5,68
5,6,
6,3,

5.2.1 五种连接方式总览

连接方式关键字本质
自然连接JOIN仅保留两表都有匹配的记录
左外连接LEFT JOIN以左表为主,右表无匹配补 NULL
右外连接RIGHT JOIN以右表为主,左表无匹配补 NULL
全外连接FULL OUTER JOIN左右并集,无匹配补 NULL
左半连接LEFT SEMI JOIN本质是嵌套查询,只输出左表字段
笛卡尔连接from A, B(不带 on)——"最废物的连接",行数 = |A| × |B|,不推荐

5.2.2 笛卡尔连接(最废物)
select student100.sno, sname, cno, grade
from student100, SC100;

结果展示(按 sno 升序,共 100 行 = 10 × 10):




5.2.3 自然连接(JOIN)
select student100.sno, sname, cno, grade
from student100 join SC100 on student100.sno=SC100.sno;
含义:学生必须存在 student100 里,且选了课(但不必有有效成绩,NULL 也会保留)。

结果(9 行)


5.2.4 左外连接(LEFT JOIN)
select student100.sno, sname, cno, grade
from student100 left join SC100 on student100.sno=SC100.sno;
含义:以 student100 为主出发,看 SC100 中有谁和它等值,返回左边的全部内容(无匹配则右字段补 NULL)。

结果(13 行)


5.2.5 右外连接(RIGHT JOIN)
select student100.sno, sname, cno, grade
from student100 right join SC100 on student100.sno=SC100.sno;
含义:以 SC100 为主出发,看 student100 中有谁和它等值,返回右边的全部内容(左表无匹配补 NULL)。

结果(11 行)


5.2.6 全外连接(FULL OUTER JOIN)
select student100.sno, sname, cno, grade
from student100 full outer join SC100 on student100.sno=SC100.sno;
含义:同时执行 LEFT JOIN 和 RIGHT JOIN(已经包含了 JOIN NOT NULL & NOT NULL 的情况)。

结果(15 行)


5.2.7 左半连接(LEFT SEMI JOIN)
select student100.sno, sname, sage, saddr
from student100 left semi join SC100
on (student100.sno = SC100.sno);
核心思想:"检查左表的每一行是否能在右表中找到匹配项,如果能,就保留左表的这一行;否则,就丢弃它。"

LEFT SEMI JOIN 的关键特性

  • 本质是嵌套查询,不是真正的 JOIN
  • 只输出左表字段,右表字段不可引用
  • HIVE 不支持多层 LEFT SEMI JOIN 嵌套(仅一次嵌套)

5.2.8 多层嵌套的两种实现方式

场景:选课人数 > 2 的有效选课学生名单

方式一:临时表(推荐)

-- 步骤 1:建立中间表(统计每门课的选课人数)
create table tempsc100 as
select cno, count(*) as cnt from SC100 group by cno;

-- 查看 tempsc100

-- 步骤 2:选出选课人数 > 2 的课程对应的学生
create table tmpst100 as
select SC100.sno from SC100 join tempsc100
  on SC100.cno = tempsc100.cno
where cnt > 2;

-- 步骤 3:LEFT SEMI JOIN 锁定最终学生名单
select sno, sname
from student100 left semi join tmpst100
  on student100.sno = tmpst100.sno;
结论:HIVE 不支持多层嵌套,只支持 LEFT SEMI JOIN 一次嵌套。因此只能通过中间表的方式实现多层嵌套。

方式二:子查询(不需要创建中间表)

select *
from student100
inner join
(
    select *
    from tempsc100
    join sc100
    on tempsc100.cno = sc100.cno
    where cnt > 2
) a
on student100.sno = a.sno;
注意:嵌套子查询中两个 SC100 都有 cno 字段,会出现二义性,必须用别名 a 隔离。

5.3 ah16 血型统计复习

重要:ah16 实操不删除。

【复习 ah16】一次性统计出所有血型的指令 Group by

select bloodtype, count(*) as cnt
from owndb.ah16
group by bloodtype;

第六章 函数与视图

6.1 条件函数:if / case when

if 函数(二分类)

if(condition, TrueValue, DefaultValue)

case when(多分支)

case <field>
  when 'value1' then 'result1'
  when 'value2' then 'result2'
  ...
  else 'default_result'
end as alias

经典案例(tb_case 表):

悟空   A   男
娜娜   A   男
宋宋   B   男
凤姐   A   女
热巴   B   女
慧慧   B   女

目标结果

dname
A21
B12

方法一:行转列后再 sum

-- 第一步:分组计数(4 行)
select dname, gender, count(*) as cnt
from tb_case
group by dname, gender;

-- 第二步:行转列
select
  dname,
  count(*) as count_numbe,
  sum(if(gender == '男', 1, 0)) as M,
  sum(if(gender == '女', 1, 0)) as F
from tb_case
group by dname;

方法二:直接用 case when 行转列

-- 写法一
select
  dname,
  sum(case gender when '男' then 1 else 0 end) as m,
  sum(case gender when '女' then 1 else 0 end) as f
from tb_case
group by dname;

-- 写法二
select
  dname,
  sum(case when gender == '男' then 1 else 0 end) as m,
  sum(case when gender == '女' then 1 else 0 end) as f
from tb_case
group by dname;

附加应用:性别缩写转换

select
  name, dname, gender,
  case gender
    when '男' then 'm'
    when '女' then 'f'
  end
from tb_case;

6.2 聚合函数与分组汇总

sum 的两种写法对比

写法含义是否正确
sum(jb + jj + tc)把三列相加后求和✔ 正确
sum(jb, jj, tc)把三列作为独立参数求和❌ 错误

max vs greatest

函数作用范围
max(col)返回列中最大的值
greatest(col1, col2, col3, ...)返回行内多个字段中最大的值

经典案例:每位员工收入最高的类型(资料 8. case_when.txt

-- 表 gz(uid, jb, jj, tc, deptno)
select
  uid,
  greatest(jb, jj, tc) as greatest_sal,
  case
    when jb == greatest(jb, jj, tc) then 'jb'
    when jj == greatest(jb, jj, tc) then 'jj'
    when tc == greatest(jb, jj, tc) then 'tc'
  end as greatest_sal_type
from gz;

配套员工-部门关联分析(gz, bm, yg 三表连接):

-- 求每部门总薪资
select
  deptno,
  sum(jb + jj + tc) as sal_sum_dept
from gz
group by deptno;

-- 求每部门不同性别员工薪资总和
select
  deptno, gender,
  sum(jb + jj + tc) as sum_sal_dept_and_gender
from (
    select gz.*, yg.gender
    from yg join gz on yg.uid = gz.uid
) t
group by deptno, gender;

6.3 视图

视图 vs 表

维度视图(虚表)表(实表)
创建语句create view v as select ...create table t as select ...
是否执行 MR不执行 MR执行 MR
查询时行为select * from 视图自动 MRselect * from table → 不启动 MR
数据存储不存储数据,仅保存定义存储物理数据

视图的特点

create view as select ... 不执行 MR

create table as select ... 执行 MR

create view as (select ...) 保持原来数据的统一,虚实结合,真正的查询对象是实表

实操

create view viewdb as
select
  dname,
  count(*) as count_numbe,
  sum(if(gender == '男', 1, 0)) as M,
  sum(if(gender == '女', 1, 0)) as F
from tb_case
group by dname;

-- 视图与表的查询对比
select * from tmp_case;       -- 不启动 MR
select * from viewdb;          -- 自动 MR


6.4 查询输出方式总结

输出方式命令存储位置
临时输出select * from ...控制台
输出到 HDFSinsert overwrite directory '目录' row format delimited fields terminated by '#' select ...HDFS 目录
HDFS → 本地hadoop fs -get HDFS目录 本地目录本地
输出到基本表create table xxx as select ...实表
输出到视图create view xx as select ...; select * from xxview;虚表(启动 MR)
临时表查询(不创建表)with t as (select ...)内存中的临时结果集

6.5 常用内置函数清单

字符串函数

函数作用示例
length(s)字符数length('hello world') → 11
concat(a, b, ...)拼接concat('hello', 'world')
trim(s)只去首尾空格(注意:不是去全部)trim(' hello ')
lpad(s, n, c)左填充至 n 位lpad('abcd', 10, '*')
rpad(s, n, c)右填充至 n 位rpad('abcd', 10, '*')
lower(s)转小写lower('Hello WORLD!')
upper(s)转大写upper('Hello WORLD!')
substr(s, start)从 start 开始截到末尾(1-based)substr('hello world', 5)' world'
substr(s, start, len)截取 len 个字符substr('hello world', 5, 3)' wo'
instr(s, sub)子串位置instr('hello', 'll') → 3

数值函数

函数作用示例
round(x, d)四舍五入(d 可为负数)round(45.836, -1) → 50.0;round(45.836, -2) → 0.0;round(95.836, -2) → 100.0
ceil(x)向上取整ceil(45.926)
floor(x)向下取整floor(45.926)

收集/转换函数

函数作用示例
size(map(1,'yom',2,'ff'))返回集合大小2
cast(x as type)类型转换cast('2019-11-21' as date)

日期函数

函数作用示例
to_date(s)转日期to_date('2019-11-28 11:23:45')
year(s) / month(s) / day(s)取年/月/日year('2019-11-28') → 2019
weekofyear(s)周数
datediff(d1, d2)日期差(天)datediff('2019-11-29','2014-11-12')
date_add(d, n)加 n 天(n 可负)date_add('2019-12-2', 2)
date_sub(d, n)减 n 天
from_unixtime(unix_timestamp(s, fmt), fmt)时间戳格式化from_unixtime(unix_timestamp('20200101','yyyyMMdd'),'yyyy-MM-dd')2020-01-01
current_date当前日期

条件函数

函数作用
coalesce(a, b, c, ...)从左到右返回第一个不为 NULL 的值
case ... when ... then ... end多分支条件

聚合函数countsumminmaxavg

表生成函数

函数作用
explode(map) / explode(array)行转列

查询优化开关(Lesson 12):

set hive.fetch.task.conversion=more;
-- 或
set hive.exec.mode.local.auto=true;
-- 简单 select 不转换为 MR

第四篇 综合实战

第七章 综合案例分析

7.1 肥胖等级数据分析(obesity_level.csv)

建表

drop table if exists feipang;

create table feipang(
  gender string,
  age int,
  height float,
  fam_his int,
  FAVC int,
  FCVC int,
  NCP int,
  CAEC string,
  SMOKE int,
  CH2O float,
  SCC int,
  FAF int,
  TUE float,
  CALC string,
  MTRANS string,
  fat_level string
)
row format delimited
fields terminated by ','
tblproperties('skip.header.line.count'='1');  -- 跳过 CSV 首行表头

load data local inpath '/home/obesity_level.csv' into table feipang;

查询基础统计

select count(*) as cnt from feipang;
select distinct(fat_level) from feipang group by fat_level;

实操题目

  1. 查询 fat_level 等级数量及占比
with TOTAL as (select count(*) as total from feipang)
select distinct(fat_level), round(count(*) / TOTAL.total, 3) as percentage
from feipang
group by fat_level;
  1. 查询 MTRANS 各类样本数
select distinct(MTRANS), count(*) as cnt_MTRANS
from feipang
group by MTRANS;
  1. 将 CAEC 中 '0' 替换为 'Never'(不增加新字段)
-- 先观察 CAEC 取值
select distinct(CAEC) from feipang;

-- 思路:先建临时表新增 CAEC_1 列,再覆盖回原表
create table feipang_new as
select *, case CAEC when '0' then 'Never' end as CAEC_1
from feipang;
-- 注意观察 CAEC=sometimes/always/frequently 的数据会不会一起
-- 携带到 CAEC_1 的字段中 → CAEC_1 中只含 Never

-- 覆盖原表(必须列出全部列)
insert overwrite table feipang
select
  gender, age, height, fam_his, FAVC, FCVC, NCP,
  CAEC_1,                              -- 替换后的列
  SMOKE, CH2O, SCC, FAF, TUE,
  CALC, MTRANS, fat_level
from feipang_new;
  1. ORC 表事务权限(ORC 表可 update / delete,textfile 不行)
create table feipang_new (stored as ORC)
as
select *, case CAEC when '0' then 'Never' end as CAEC_1
from feipang;

7.2 身份证信息处理

建表

create table cid_info(id int, cid string)
row format delimited fields terminated by '#';

load data local inpath '/home/cid.txt' into table cid_info;

-- 观察 cid 长度(会有空格,要确定从哪开始计算)
select distinct(length(cid)) from cid_info;

题目 1:截取 cid 的 8 位出生年月日作为 birthday

select cid, substr(cid, 8, 8) as birthday from cid_info;

alter table cid_info add columns(birthday string);

-- 只插一列(不用中间表)——没有 into
insert overwrite table cid_info
select id, cid, substr(cid, 8, 8) as birthday from cid_info;

题目 2:将截取的 birthday 转换为 yyyy-MM-dd 格式

alter table cid_info add columns(birth_date string);

insert overwrite table cid_info
select
  id, cid, birthday,
  from_unixtime(unix_timestamp(substr(cid, 8, 8), 'yyyyMMdd'), 'yyyy-MM-dd') as birth_date
from cid_info;

题目 3:将 birthday 拆分为 year、month、day

alter table cid_info add columns(birth_year int, birth_month int, birth_day int);

insert overwrite table cid_info
select
  id, cid, birthday, birth_date,
  year(birth_date) as birth_year,
  month(birth_date) as birth_month,
  day(birth_date) as birth_day
from cid_info;

题目 4:计算实岁和虚岁

alter table cid_info add columns(age_shi float, age_xu int);

insert overwrite table cid_info
select
  id, cid, birthday, birth_date,
  birth_year, birth_month, birth_day,
  round(datediff(current_date, birth_date) / 365, 1) as age_shi,
  year(current_date) - birth_year as age_xu
from cid_info;

7.3 结婚离婚数据查询综合实训

资料 7 结婚离婚数据查询综合实训.txt

建表(70+ 字段,按季度拆分每省年度数据):

create table marriage(
  province string,
  M07Q1 int, D07Q1 int, M07Q2 int, D07Q2 int,
  M07Q3 int, D07Q3 int, M07Q4 int, D07Q4 int,
  -- ... 省略 M08Q1..M20Q3 共 14 年的所有季度字段
  M20Q1 int, D20Q1 int, M20Q2 int, D20Q2 int, M20Q3 int, D20Q3 int
)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'
tblproperties('skip.header.line.count'='2');

load data local inpath '/opt/data/marriageclean.txt' overwrite into table marriage;

查询

set hive.cli.print.header=true;
select province, M07Q1, D07Q1, M07Q2, D07Q2, M07Q3, D07Q3, M07Q4, D07Q4
from marriage limit 10;

select count(*) from marriage;

-- 2007 年各省结婚/离婚季度合计
select province, M07Q1+M07Q2+M07Q3+M07Q4 from marriage;

典型分析:07 年结婚数最高的省份

create table Y07MD as
select province, avg(M07Q1+M07Q2+M07Q3+M07Q4) as M07,
       avg(D07Q1+D07Q2+D07Q3+D07Q4) as D07
from marriage
group by province
order by M07;

select max(M07) from Y07MD;     -- 1806787.0
select province from Y07MD where M07 = 1806787.0;  -- 山东省

多年汇总

create table allyearM as
select province,
  sum(M07Q1+M07Q2+M07Q3+M07Q4) as M07,
  sum(M08Q1+M08Q2+M08Q3+M08Q4) as M08,
  -- ... 14 年
  sum(M20Q1+M20Q2+M20Q3) as M20
from marriage
group by province
order by M07;

select * from allyearM limit 10;
错误示例select max(M07, M08, M09, M10, M11) from allyearM;
max 不能接受多列参数。

第八章 半结构化数据处理

8.1 JSON 数据处理

JSON 解析的两种方式

JAR 包方式:自定义 RegexSerDe 解析

get_json_object 函数:函数式字段提取

应用案例:影评库 users.dat / movies.dat / ratings.dat(详见第九章)。

8.2 字符串函数与数据清洗

字符串函数复习(见 §6.5)。

特别注意

trim 只去首尾空格

length 计算字符数(含空格),如 length(' hello') → 6

concat 拼接时空格会保留,必要时先 trim


第九章 影评综合案例

资料 第11章 影评案例综合应用.txt

9.1 数据说明

数据文件格式行数字段
users.dat2::M::56::16::700726040UserID BigInt, Gender String, Age Int, Occupation String, Zipcode String
movies.dat`2::Jumanji (1995)::AdventureChildren'sFantasy`3883MovieID BigInt, Title String, Genres String
ratings.dat1::1193::5::9783007601000209UserID BigInt, MovieID BigInt, Rating Double, Timestamped String
问题:HIVE 不支持解析多字节分隔符 '::',必须用 RegexSerDe 或先 shell 清洗成单分隔符。

9.2 建表(RegexSerDe)

drop database if exists movie;
create database if not exists movie;
use movie;

-- 用户表
create table t_user(
  userid bigint, sex string, age int, occupation string, zipcode string)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties(
  'input.regex'='(.*)::(.*)::(.*)::(.*)::(.*)',
  'output.format.string'='%1$s %2$s %3$s %4$s %5$s')
stored as textfile;

-- 电影表
create table t_movie(
  movieid bigint, moviename string, movietype string)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties(
  'input.regex'='(.*)::(.*)::(.*)',
  'output.format.string'='%1$s %2$s %3$s')
stored as textfile;

-- 评分表
create table t_rating(
  userid bigint, movieid bigint, rate double, times string)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties(
  'input.regex'='(.*)::(.*)::(.*)::(.*)',
  'output.format.string'='%1$s %2$s %3$s %4$s')
stored as textfile;

-- 装载
load data local inpath '/warehouse/users.dat'  into table t_user;
load data local inpath '/warehouse/movies.dat' into table t_movie;
load data local inpath '/warehouse/ratings.dat' into table t_rating;

select * from t_user limit 5;
select * from t_movie limit 5;
select * from t_rating limit 5;

9.3 十大分析需求

(1) 被评分次数最多的 10 部电影

create table answer2 as
select a.moviename as moviename, count(a.moviename) as total
from t_movie a
join t_rating b on a.movieid = b.movieid
group by a.moviename
order by total desc
limit 10;

select * from answer2;

(2) 男性/女性评分最高的 10 部电影

-- 女性
create table answer3_F as
select 'F' as sex, c.moviename as name,
       avg(a.rate) as avgrate, count(c.moviename) as total
from t_rating a
join t_user b  on a.userid  = b.userid
join t_movie c on a.movieid = c.movieid
where b.sex = 'F'
group by c.moviename
having total >= 50
order by avgrate desc
limit 10;

-- 男性
create table answer3_M as
select 'M' as sex, c.moviename as name,
       avg(a.rate) as avgrate, count(c.moviename) as total
from t_rating a
join t_user b  on a.userid  = b.userid
join t_movie c on a.movieid = c.movieid
where b.sex = 'M'
group by c.moviename
having total >= 50
order by avgrate desc
limit 10;

(3) movieid = 2116 各年龄段平均影评

create table answer4 as
select a.age as age, avg(b.rate) as avgrate
from t_user a
join t_rating b on a.userid = b.userid
where b.movieid = 2116
group by a.age;

(4) 影评最多的女性评分最高的 10 部电影的平均影评分

-- A:最喜欢看电影的女性
select a.userid, count(a.userid) as total
from t_rating a
join t_user b on a.userid = b.userid
where b.sex = 'F'
group by a.userid
order by total desc
limit 1;   -- 假设 userid = 1150

-- B:该女性评分最高的 10 部电影
create table answer5_B as
select a.movieid as movieid, a.rate as rate
from t_rating a
where a.userid = 1150
order by rate desc
limit 10;

-- C:求出 B 中 10 部电影的平均影评分
create table answer5_C as
select b.movieid as movieid, c.moviename as moviename, avg(b.rate) as avgrate
from answer5_B a
join t_rating b on a.movieid = b.movieid
join t_movie  c on b.movieid = c.movieid
group by b.movieid, c.moviename;

(5) 好片(评分 ≥ 4.0)最多的年份中最好看的 10 部电影

-- A:截取年份
create table answer6_A as
select a.movieid as movieid, a.moviename as moviename,
       substr(a.moviename, -5, 4) as years,
       avg(b.rate) as avgrate
from t_movie a
join t_rating b on a.movieid = b.movieid
group by a.movieid, a.moviename;

-- B:好片最多的年份
select years, count(years) as total
from answer6_A a
where avgrate >= 4.0
group by years
order by total desc
limit 1;   -- 假设 = 1998

-- C:该年评分最高的 10 部电影
create table answer6_C as
select a.moviename as name, a.avgrate as rate
from answer6_A a
where a.years = 1998
order by rate desc
limit 10;

(6) 1997 年评分最高的 10 部 Comedy 类电影

-- A:联合电影类型
create table answer7_A as
select b.movieid as id, b.moviename as name,
       b.years as years, b.avgrate as rate, a.movietype as type
from t_movie a
join answer6_A b on a.movieid = b.movieid;

-- B:筛选 + 排序
create table answer7_B as
select t.id as id, t.name as name, t.rate as rate
from answer7_A t
where t.years = 1997 and instr(lcase(t.type), 'comedy') > 0
order by rate desc
limit 10;

(7) 各类型电影中评价最高的 5 部(TopN)

-- A:裂变电影类型
create table answer8_A as
select a.id as id, a.name as name, a.years as years,
       a.rate as rate, tv.type as type
from answer7_A a
lateral view explode(split(a.type, '\\|')) tv as type;

-- B:按类型分组编号
create table answer8_B as
select id, name, years, rate, type,
       row_number() over (distribute by type sort by rate desc) as num
from answer8_A;

-- C:取每组前 5
select a.* from answer8_B a where a.num <= 5;

(8) 各年评分最高的电影类型

-- A:按 (年份, 类型) 分组计算平均评分
create table answer9_A as
select a.years as years, a.type as type, avg(a.rate) as rate
from answer8_A a
group by a.years, a.type
order by rate desc;

-- B:按年份编号
create table answer9_B as
select years, type, rate,
       row_number() over (distribute by years sort by rate) as num
from answer9_A;

-- C:取每年最高类型
select * from answer9_B where num = 1;

(9) 每个地区最高评分的电影名(存入 HDFS)

-- A:三表联合,计算每个 (地区, 电影) 平均评分
create table answer10_A as
select c.movieid, c.moviename, avg(b.rate) as avgrate, a.zipcode
from t_user a
join t_rating b on a.userid  = b.userid
join t_movie  c on b.movieid = c.movieid
group by a.zipcode, c.movieid, c.moviename;

-- B:按地区分组编号
create table answer10_B as
select movieid, moviename, avgrate, zipcode,
       row_number() over (distribute by zipcode sort by avgrate) as num
from answer10_A;

-- C:取 num = 1 的行写入 HDFS
insert overwrite directory '/movie/answer10/'
select t.* from answer10_B t where t.num = 1;

hadoop fs -ls  /movie/answer10/
hadoop fs -cat /movie/answer10/000000_0

第五篇 总复习

第十章 知识体系总结

10.1 表的创建与存储

知识点关键点
数据库存储位置默认 /user/hive/warehouse/xxx.db/,可 location 指定
表/外部表 location写在表级,location 最好精确到表名级,含约束时必须放最后
表/外部表/分区表/桶表数据装载与表的内容匹配
分区表/桶表查看内容partition 目录查看 vs 桶号文件 00000_0

10.2 四种表类型

类型关键字数据管理
普通表create tabledrop 级联删除
外部表create external table ... locationdrop 不级联(原理:引用切断,存储位置仍存在)
分区表partitioned by按字段值目录切分
桶表clustered by ... into n buckets按哈希分散到固定数量文件

10.3 数据输入与输出方法

输入(数据导入)

方法命令
HDFS puthadoop fs -put 本地文件 Directory
LOAD DATAload data local inpath '/data/st1.txt' into table student;
INSERTinsert into ... select ...
HDFS cp/mvhadoop fs -cp /hdfs/path /target

输出(查询导出)

方法命令
控制台临时输出select * from ...
输出到 HDFSinsert overwrite directory '目录' row format delimited fields terminated by '#' select ...
输出到视图create view xx as select ...
输出到实表create table xx as select ...
WITH 临时查询with t as (select ...) select * from t

10.4 HQL 增删改查

  1. ORC 表开放事务权限后,可执行 updatedeletetextfile 不行
  2. insert 没有问题(任何存储格式)
  3. 查询思路:distinctcountgroup byorder bylimit
  4. 函数应用:maxminavggreatestifcase whenlengthconcattrimlowerupperinstrsubstr

10.5 笛卡尔连接 / 五种 JOIN 总结

连接方式关键字特性
笛卡尔连接from A, B(不带 on行数 =
自然连接JOIN ... ON仅保留匹配
左外连接LEFT JOIN左表为主
右外连接RIGHT JOIN右表为主
全外连接FULL OUTER JOIN左右并集
左半连接LEFT SEMI JOIN仅输出左表字段,本质是嵌套查询

10.6 静态分区 vs 动态分区

维度静态分区动态分区
Schema相同相同
数据装载速度较快(直接挂目录)较慢(需 MR)
数据控制精度精准(配合 where 过滤不干净数据)宽松(依赖源数据)
典型语句load data ... partition(addr='xx')insert ... partition(addr)

附录:参考资料清单

类别文件
集群与 HDFS00 集群启动.txt0 hdfs shell操作.txt
HIVE 基础指令1 HIVE指令实际操练1.txt2 表的创建与数据装载操作.txt
复杂类型3 三种复杂结构的数据输入操作实践.txt3 静态分区表的管理.txt
桶表4 桶表的数据装载及分桶显示.txt4 桶表的数据装载及分桶显示(1).txt
JOIN 案例5 hive连接的案例设计.txt
函数与查询6 查询软件实践.txt8. case_when.txt8.1 source.txt
综合实训7 结婚离婚数据查询综合实训.txt第11章 影评案例综合应用.txtjson.txt
实操数据ah16(体检数据)、obesity_level.csv学生体检数据普通表和分区表导入.txt
HIVE 配置执行命令集合.txt
教材 PPT02 Hadoop与HIve.pptx03 HIVE的体系结构与安装.pptx第4-10章 Hive 系列

附录:原始笔记 Lesson 索引

Lesson主题详见本文档
Lesson 1前沿技术科普§1.1
Lesson 2三级模式、数据分类、HIVE 三种部署§1.2、§1.3、§2.2
Lesson 3集群启停、HIVE 配置、metastore§2.3、§2.4、§3.1
Lesson 4数据导入、location 规范、复杂数据类型§3.3、§3.4、§3.5
Lesson 5表复制、Array/Map/Struct 嵌套§3.6、§3.5.4
Lesson 6外部表、load data、ah16 实操§4.1、§4.2.6
Lesson 7静态分区表§4.2.1-§4.2.4
Lesson 8动态分区表、桶表、五种 JOIN§4.2.5、§4.3、§5.2.1
Lesson 9桶表陷阱、数据导出§4.3.3、§5.1
Lesson 10JOIN 五种连接、LEFT SEMI JOIN§5.2
Lesson 11视图、case when、聚合函数§6.1、§6.3
Lesson 12查询输出、肥胖数据实战§6.4、§7.1
Lesson 13ORC 表、CAEC 字段替换§7.1
Lesson 14身份证信息处理§7.2
Lesson 15JSON 处理§8.1、§9
Lesson 16字符串函数、知识体系总结§6.5、第十章

最后修改:2026 年 08 月 04 日
如果觉得我的文章对你有用,请随意赞赏