Hive 从入门到实战(二):DDL 数据库与表操作,内部表 vs 外部表一文讲透
这是《Hive 从入门到实战》系列第 2 篇。上一篇装好了 Hive,这一篇解决:库和表怎么建、怎么改、怎么删,以及面试必考的内部表 vs 外部表。
目录
- 一、数据库操作:增删改查
- 二、建表语法全景:把每块积木拆给你看
- 三、内部表 vs 外部表(面试高频)
- 四、表的复制:CTAS vs LIKE
- 五、查看表与修改表
- 六、删除表与清空表:drop vs truncate
- 七、面试加餐
- 八、总结
一、数据库操作:增删改查
1.1 创建数据库:四种方式
完整语法:
CREATE[REMOTE](DATABASE|SCHEMA)[IFNOTEXISTS]database_name[COMMENTdatabase_comment][LOCATION hdfs_path][WITHDBPROPERTIES(property_name=property_value,...)];四种常用方式:
-- 方式1:最朴素,不指定任何东西createdatabasedb_test1;-- 方式2:指定在 HDFS 上的存储路径createdatabasedb_test2 LOCATION'/db_test2';-- 方式3:附加自定义属性(kv 键值对)createdatabasedb_test3withdbproperties('create_date'='2026-08-28');-- 方式4:加注释,方便别人看懂这个库是干嘛的createdatabasedb_test4comment'测试数据库';小细节:
IF NOT EXISTS建议永远带上——库已存在时不再报错,脚本可重复执行。
不指定 LOCATION 时,库对应的数据目录默认是:
/user/hive/warehouse/db_test1.db也就是上一篇配置的hive.metastore.warehouse.dir下加一个.db后缀目录。
1.2 查看数据库
showdatabases;-- 列出所有库showdatabaseslike'db*';-- 模糊匹配输出:
OK db_test1 db_test2 db_test3 db_test4 default Time taken: 0.02 seconds, Fetched: 5 row(s)like通配符规则:*匹配任意字符,|表示"或"。
1.3 查看库详情
descdatabasedb_test3;-- 基础信息descdatabaseextendeddb_test3;-- 详细信息(含 dbproperties)输出:
OK db_name comment location owner_name owner_type parameters db_test3 hdfs://master:9000/user/hive/warehouse/db_test3.db root USER {create_date=2026-08-28}extended比desc database多显示自定义的 dbproperties,排查"这个库是谁建的、什么时候建的"时很有用。
1.4 修改数据库
-- 改属性alterdatabasedb_test3setdbproperties('create_date'='2026-08-29');-- 改 HDFS 路径(有坑!往下看)alterdatabasedb_test2setlocation'hdfs://master:9000/test2';修改 LOCATION 的两个大坑(真实报错实录):
坑一:必须写完整的绝对 URI,写相对路径直接报错:
alterdatabasedb_test2setlocation'/test2';FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. {0} is not absolute. Please specify a complete absolute uri. /test2坑二:改完不会马上在 HDFS 上创建新目录,老目录里的数据也不会搬走。只有之后新创建的表才会落到新路径。
一句话:alter ... set location只改"户口登记",不搬家。
1.5 删除数据库:RESTRICT vs CASCADE
DROP(DATABASE|SCHEMA)[IFEXISTS]database_name[RESTRICT|CASCADE];两种模式:
| 模式 | 行为 | 默认? |
|---|---|---|
| RESTRICT | 严格模式:库不为空就删失败 | 是 |
| CASCADE | 级联模式:把库连同里面的表一起删光 | 否 |
实测:
dropdatabasedb_test1;-- 空库,直接删掉dropdatabasedb_test2;-- db_test2 里有表,报错!FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. InvalidOperationException(message:Database db_test2 is not empty. One or more tables exist.)dropdatabasedb_test2CASCADE;-- 连锅端,库和表全删记忆口诀:默认 RESTRICT 不删库,CASCADE 级连连锅端。
1.6 切换数据库
usebigdata;-- 切到 bigdata 库usedefault;-- 切回默认库不切换时建的表都进default库,建议养成先use再操作的习惯。
二、建表语法全解
2.1 完整语法
CREATE[TEMPORARY][EXTERNAL]TABLE[IFNOTEXISTS][db_name.]table_name[(col_name data_type[COMMENTcol_comment],...)][COMMENTtable_comment][PARTITIONEDBY(col_name data_type,...)][CLUSTEREDBY(col_name,...)[SORTEDBY(col_name[ASC|DESC],...)]INTOnum_buckets BUCKETS][[ROWFORMAT row_format][STOREDASfile_format]][LOCATION hdfs_path][TBLPROPERTIES(property_name=property_value,...)];看着吓人,其实就是一个"积木清单",大部分都是可选的。逐块拆解:
| 积木 | 含义 | 不写会怎样 |
|---|---|---|
| EXTERNAL | 建外部表 | 默认建内部表(管理表) |
| PARTITIONED BY | 建分区表 | 普通表(第 4 篇详解) |
| CLUSTERED BY … INTO n BUCKETS | 建分桶表 | 不分桶(第 4 篇详解) |
| ROW FORMAT | 指定数据文件里行列怎么切分 | 默认^A控制符切分,几乎必须写 |
| STORED AS | 指定文件格式 | 默认 TEXTFILE(第 5 篇详解) |
| LOCATION | 指定数据在 HDFS 的路径 | 默认 warehouse 目录下 |
| TBLPROPERTIES | 表级 kv 属性 | 无 |
2.2 数据类型:基本类型 + 复杂类型
基本类型和 MySQL 差不多,重点关注几个 Hive 特色的:
TINYINT / SMALLINT / INT / BIGINT -- 整数 FLOAT / DOUBLE / DECIMAL(p,s) -- 小数,金额建议 DECIMAL BOOLEAN -- 布尔 STRING / VARCHAR / CHAR -- 字符串,Hive 更常用 STRING TIMESTAMP / DATE -- 时间复杂类型是 Hive 的招牌,一个字段可以装"一堆值":
| 类型 | 写法 | 类比 | 元素分隔符 |
|---|---|---|---|
| ARRAY | array<string> | 一个字段里存一串同类型值,如朋友列表 | , |
| MAP | map<string,int> | 一个字段里存 kv 对,如 {语文:90} | ,与: |
| STRUCT | struct<street:string,city:string> | 一个字段里打包多个命名字段 | , |
| UNIONTYPE | uniontype<int,string> | 多选一 | - |
2.3 ROW FORMAT:数据怎么被切成行列
这是建表最容易出错的地方。Hive 读 HDFS 文本文件时,全靠这些分隔符切分:
rowformat delimitedfieldsterminatedby','-- 列分隔符:每行的字段用什么隔开collection itemsterminatedby','-- array/map/struct 元素之间的分隔符mapkeysterminatedby':'-- map 中 key 和 value 的分隔符linesterminatedby'\n'-- 行分隔符关键理解:row format是读文件时的切分规则。你的 CSV 文件用逗号分隔,建表就写fields terminated by ',';写错了,查出来的数据就"错位"了。
2.4 建表实战
-- 建库createdatabaseIFNOTEXISTSbigdata;-- 内部表(默认)createtableifnotexistsbigdata.students(id stringcomment'学号',name stringcomment'姓名',ageintcomment'年龄',sex stringcomment'性别',clazz stringcomment'班级');-- 验证:insert 一条数据insertintostudentsvalues('1500100001','施笑槐',22,'女','文科一班');输出:
WARNING: Hive-on-MR is deprecated... Query ID = root_xxx Total jobs = 3 Launching Job 1 out of 3 ... OK Time taken: 21.336 seconds注意:插入一条数据也要跑 MapReduce,这就是上一篇说的"Hive 不适合逐行写,适合批量分析"的直观体现。
再建一张外部表(EXTERNAL),并直接把文件 put 进它的目录:
createEXTERNALtableifnotexistsbigdata.students2(id stringcomment'学号',name stringcomment'姓名',ageintcomment'年龄',sex stringcomment'性别',clazz stringcomment'班级')rowformat delimitedfieldsterminatedby',';# 直接用 hdfs 命令把数据丢进表目录——Hive 都不用出手hdfs dfs-putstudent.csv /user/hive/warehouse/bigdata.db/students2/put 完立刻能查到数据!这个现象正好引出下一节的核心概念:Hive 表只是 HDFS 目录的"外壳"。
三、内部表 vs 外部表(面试高频)
3.1 先给定义,再讲规则
- 内部表(管理表 / Managed Table):Hive完全接管这张表——元数据和 HDFS 数据都归 Hive 管
- 外部表(External Table):Hive只接管元数据——HDFS 上的数据 Hive 只"登记",不"拥有"
类比:
- 内部表像租房:房子(数据)的进出、退租(drop)都由你和房东(Hive)绑定,退租时家具全部搬走
- 外部表像只登记门牌号:Hive 只知道"数据在哪个目录",数据本身别人也能放、也能读,drop 表只是撕掉登记条,数据原封不动
3.2 drop 之后的区别(亲手验证)
-- 删内部表:元数据 + HDFS 数据 一起消失droptableifexistsstudents;-- 删外部表:只删元数据,HDFS 数据还在droptablestudents2;验证外部表的数据确实还在:
hdfs dfs-ls/user/hive/warehouse/bigdata.db/students2/# 文件 student.csv 依然存在!口诀:内管到底,外只挂名——drop 内部表连数据一起删,drop 外部表数据原地不动。
3.3 怎么选:使用场景
| 场景 | 选型 | 理由 |
|---|---|---|
| 原始日志、业务数据(多工具共享:Spark、MapReduce 也要读) | 外部表 | 防止误删源数据;数据生命周期不归 Hive 管 |
| 分析过程中的中间结果表、临时表 | 内部表 | 用完即删,drop 顺带清数据,不留垃圾 |
经验法则:越靠近源头的数据越用外部表,越靠近计算结果的数据越用内部表。
四、表的复制:CTAS vs LIKE
-- CTAS:复制表结构 + 复制表数据createtablestudents3asselect*fromstudents2;-- LIKE:只复制表结构,数据为空createtablestudents4likestudents2;输出:
-- students3:查询有全部数据 select * from students3; -- 行数与 students2 相同 -- students4:查询是空表 select * from students4; -- 0 row口诀:AS 连数据一起搬,LIKE 只搬个壳。
注意:CTAS 不支持外部表(not supported for external tables)。
五、查看表与修改表
5.1 查看表
showtables;-- 当前库所有表showtableslike'students*';-- 模糊查descstudents;-- 看表结构(字段)descFORMATTED students;-- 看表的详细信息(格式化展示)desc formatted输出节选(重点看这几行):
# Detailed Table Information Table Type: MANAGED_TABLE -- 内部表;外部表显示 EXTERNAL_TABLE # Storage Information Location: hdfs://master:9000/user/hive/warehouse/bigdata.db/students InputFormat: org.apache.hadoop.mapred.TextInputFormat OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat排查"这表是内部还是外部、数据在哪、什么格式",desc formatted一条命令全搞定。
5.2 修改表
-- ① 重命名ALTERTABLEstudentsRENAMETOstudents1;-- ② 修改表属性altertablestudents1settblproperties('create_date'='2026-08-28');-- ③ 新增列altertablestudents4addCOLUMNS(scorefloatcomment'成绩');-- ④ 更新列:改名改类型(sex 改名为 gender)altertablestudents1 changecolumnsex gender string;-- ⑤ 替换列:整表字段直接替换成新定义(危险操作,慎用)altertablestudents4REPLACECOLUMNS(id string,name string);几点提醒:
- Hive 没有"删除某一列"的语法,想删列只能用
REPLACE COLUMNS重写整份字段清单 change column支持移动列位置:[FIRST|AFTER column_name]- 修改表只改元数据,HDFS 里的原始文件不会变,所以改列名/加列后要确认老数据能对上
六、删除表与清空表:drop vs truncate
-- drop:删表(元数据没了,内部表数据也没了)DROPTABLE[IFEXISTS]table_name[PURGE];-- truncate:只清数据,表壳和字段还在TRUNCATE[TABLE]table_name[PARTITIONpartition_spec];truncatetablestudents3;select*fromstudents3;-- 空表,但 desc students3 结构还在关键区别(面试常问):
| 对比 | drop table | truncate table |
|---|---|---|
| 表结构 | 删除 | 保留 |
| 数据 | 删除 | 清空 |
| 能否用于外部表 | 能(数据不删) | 不能,只对内部表有效 |
为什么 truncate 对外部表无效?回想 3.1 的定义——外部表的数据不归 Hive 管,Hive 自然无权清空它。
七、面试加餐
Q1:内部表和外部表的区别?
答:内部表 Hive 完全接管元数据和数据;外部表只接管元数据。drop 内部表时元数据和 HDFS 数据一起删除,drop 外部表只删元数据、HDFS 数据保留。
Q2:什么场景用外部表?
答:多工具共享的原始数据(日志、业务抽数),防止 drop 表误删源数据;Hive 只做分析不做数据所有权管理。
Q3:drop database 会不会把表删掉?
答:默认 RESTRICT 模式下,非空库删不掉;加 CASCADE 才会级联删除库中所有表。
Q4:CTAS 和 LIKE 的区别?
答:CTAS 复制结构和数据;LIKE 只复制结构。
Q5:Hive 能删列吗?
答:没有单列删除语法,用 REPLACE COLUMNS 重写字段清单;本质只改元数据,底层文件不动。
八、总结
- 库操作四件套:
create(带 IF NOT EXISTS)、show、desc database extended、drop(RESTRICT/CASCADE) alter ... set location只改登记不搬家,且必须写绝对 URI- 建表积木:EXTERNAL / PARTITIONED BY / CLUSTERED BY / ROW FORMAT / STORED AS / LOCATION
- 内部表全托管,外部表只挂名:drop 行为差异是核心考点
- CTAS 搬结构+数据,LIKE 只搬结构;truncate 只清内部表数据