4.1 数据库与表操作:归属与结构


4.1 数据库与表操作:归属与结构

本节摘要:库与表的 DDL 在 Hive 里有双重身份:Metastore 里的一条登记、HDFS 上的一个目录。本节过一遍常用语法,重点讲内部表与外部表的所有权差异及选型决策、LIKE 与 CTAS 两种结构复用方式、ALTER 家族能改什么不能改什么,并用 DESCRIBE FORMATTED 检验每条 DDL 留下的物理痕迹。

建表语句的物理含义

先建本章的示例表,一张完整的订单明细表:

CREATE DATABASE IF NOT EXISTS mall; CREATE TABLE mall.orders ( order_id BIGINT, customer_id STRING, region STRING, amount DECIMAL(10,2), created_at TIMESTAMP ) COMMENT '订单明细表 按天分区' PARTITIONED BY (dt STRING) STORED AS ORC TBLPROPERTIES ('orc.compress' = 'ZLIB');

执行成功后发生了两件事:Metastore 的 TBLS 表里多了一条记录(列定义、SerDe、存储格式、表属性),HDFS 上多了一个目录(默认路径为仓库根下的 mall.db 子目录再接 orders)。DESCRIBE FORMATTED 是验证这两个层面的万能命令

DESCRIBE FORMATTED mall.orders;

输出里值得认识的字段:Table Type(MANAGED_TABLE 或 EXTERNAL_TABLE)、Location(HDFS 目录)、Table Parameters(注释、统计、事务标记)、Storage Information 里的 InputFormat 与 OutputFormat(ORC 与 TextFile 在这里区分)。排错时"表在不在、指向哪、什么格式"三问,一条命令全答。

内部表与外部表:所有权的分界

Hive 的表分两类,差异只有一个词:数据归谁管。

-- 内部表 也称管理表 CREATE TABLE mall.orders_managed (LIKE 结构同上); -- 外部表 加一个关键字 CREATE EXTERNAL TABLE mall.orders_ext ( order_id BIGINT, customer_id STRING ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/data/raw/orders';

内部表:Hive 拥有数据。DROP TABLE 时,HDFS 目录连同数据一起删除。外部表:Hive 只登记结构,数据属于外部流程(比如 Flume 落地的日志目录、另一个团队维护的共享数据集)。DROP TABLE 只删 Metastore 登记,目录原封不动。

选型决策的实质是回答"谁对这段数据的生命周期负责":

场景 推荐 理由
ETL 中间结果、汇总表 内部表 生命周期完全跟随作业,DROP 即清理
原始日志、多引擎共享数据 外部表 数据由落地流程拥有,Hive 只是读者之一
探索性临时表 内部表 用完即弃,避免 HDFS 垃圾堆积
需要重建表结构 先外部化或备份 误 DROP 内部表等于数据火化

一个救急技巧:内部表误删后,若只是一张由其他数据可重建的汇总表,重跑作业即可;若是原始数据,只能指望回收站或副本。所以生产规范通常写成一条:凡是不可再生的数据,一律外部表加独立目录

两者还能互相转换,但转换只改 Metastore 里的类型标记与删除行为,不动数据文件:

ALTER TABLE mall.orders SET TBLPROPERTIES ('EXTERNAL' = 'TRUE');

复用结构的两种方式

LIKE 复制表结构,不复制数据也不复制分区数据,但保留列与格式定义:

CREATE TABLE mall.orders_backup LIKE mall.orders;

CTAS(Create Table As Select)建表同时灌数,列名与类型由查询推导:

CREATE TABLE mall.north_orders STORED AS ORC AS SELECT order_id, customer_id, amount FROM mall.orders WHERE region = 'north';

CTAS 是 ETL 里的高频句式,但从翻译官视角要看清它的两面:它把"建表加插入"合并成一次提交,省去两段编译;代价是列类型由推导决定,DECIMAL 精度、NULL 语义可能与手工建表有出入。核心表建议先显式 CREATE 再 INSERT INTO,中间表随意 CTAS。

注意 CTAS 不能直接带 PARTITIONED BY 子句(各版本行为不同,Hive 3 已支持动态分区 CTAS,但保守写法仍是先建分区表再插入),这正好引出第 4.2 节的动态分区话题。

ALTER 家族的能力边界

表不是不能改,而是每次改动都要过"元数据变还是数据变"这道安检:

ALTER TABLE mall.orders ADD COLUMNS (channel STRING); -- 只改元数据 ALTER TABLE mall.orders CHANGE COLUMN amount amount DECIMAL(12,2); -- 只改元数据 但旧数据按新类型读 ALTER TABLE mall.orders ADD PARTITION (dt = '2026-01-16'); -- 建目录 空的 ALTER TABLE mall.orders DROP PARTITION (dt = '2026-01-10'); -- 删目录带数据 内部表真删 ALTER TABLE mall.orders SET TBLPROPERTIES ('comment' = 'v2'); -- 改属性

能改与不能改的分界线:只影响"怎么读"的可以改,影响"已存字节怎么解释"的要谨慎。加列安全(旧文件里没有这列,读出 NULL);改类型是读时模式的深水区——旧文件里的字节按新类型重新解释,INT 改 BIGINT 平安无事,STRING 改 INT 就会出现大面积 NULL;改存储格式只对新写入生效,旧文件保持旧格式,同一张表里两种格式并存是查询报错的经典来源。

库级操作与命名空间

库(DATABASE,别名 SCHEMA)在 HDFS 上是一个目录前缀,在 Metastore 里是命名空间:

CREATE DATABASE IF NOT EXISTS sales LOCATION '/data/warehouse/sales'; USE sales; SHOW TABLES IN sales; ALTER DATABASE sales SET DBPROPERTIES ('owner' = 'team-a');

工程上的库不是技术分组,而是团队与环境的边界:按团队分库(sales、risk、growth)配合权限模型(第 8 章),按环境分库(sales_dev、sales_prod)防止误操作。USE 只对当前会话生效,生产脚本里习惯写全限定名 mall.orders,不依赖会话状态——脚本可重放性优先。

与编译流水线的回环

DDL 看似与"SQL 翻译"无关,其实是流水线的地基:第 2 章讲过,语义分析向 Metastore 核对的每个事实(表存在、列类型、分区键、路径)都是 DDL 写进去的。本章后面三节讲的分区、分桶、视图,也全部以"改 Metastore 登记加 HDFS 布局"的方式影响查询的翻译结果。改一次 DDL,之后所有查询的执行计划都随之而变——这是建表设计值得慎重的根本原因。

本节要点回顾

  • 双重身份:每条建表 DDL 同时写 Metastore 登记与 HDFS 目录,DESCRIBE FORMATTED 一次验两层;
  • 所有权分界:内部表数据随表删,外部表只删登记;不可再生的数据一律外部表;
  • LIKE 复结构 CTAS 建且灌:CTAS 省一次编译但类型靠推导,核心表显式建;
  • ALTER 看安检线:只影响读的放心改,影响字节解释的(改类型、改格式)要评估旧文件;
  • 库是团队与环境边界:脚本里写全限定名,不依赖会话状态;
  • DDL 是编译的地基:语义分析核对的所有事实都来自 DDL 的登记。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U