本节摘要:视图是存放在 Metastore 里的一段查询定义,编译期被原样展开进你的语句,不占任何存储;索引曾经是 Hive 补救随机访问的方案,因为维护成本高、收益不稳定,已让位于分区裁剪与列存跳读。本节用 EXPLAIN 验证视图的展开机制,讲视图的三类工程用法与风险,再解释索引为何退役、物化视图为何登场。
先建一个带业务口径的视图——"高价值客户订单":
CREATE VIEW mall.vip_orders AS SELECT o.order_id, o.customer_id, o.amount, o.dt FROM mall.orders o JOIN mall.customers c ON o.customer_id = c.customer_id WHERE c.vip_level >= 3 AND o.amount > 100;
查询这个视图:
EXPLAIN SELECT dt, COUNT(*) FROM mall.vip_orders WHERE dt = '2026-01-15' GROUP BY dt;
EXPLAIN 输出里找不到任何"视图算子":你看到的是 orders 与 customers 两张物理表的 TableScan、完整的 Join 算子树、以及内外两层 WHERE 合并后的 Filter。视图在语义分析阶段被展开成子查询,之后走的是与手写等价 SQL 完全相同的编译流程。它像一个编译期的宏:定义一次,处处展开。
展开机制推出三条硬性质。第一,视图零存储:查询视图的代价等于查询其定义的代价,一分不多一分不少。第二,视图自带谓词合并:你传进来的 dt 条件与视图内的 vip 条件会在优化器手里一起下推(都有单侧可推的性质时)。第三,视图的编译有绑定风险:底层表改列名,视图当场编译失败;底层表加列且视图用星号,视图含义悄悄漂移。核心视图必须纳入变更管理,这是第 8 章数仓治理的话题。
口径固化。业务里"活跃用户""高价值订单"这类定义会出现在几十条 SQL 里,口径一变全要改。把口径写成视图,下游统一引用视图名,口径变更只改一处。数仓分层里 DWS 层对 DWD 层的轻度汇总,经常先以视图形态存在,验证稳定后再物化成表。
权限与安全边界。敏感列不希望全员可见——建一个脱敏视图(手机号只露后四位),普通分析师授权到视图,底层表权限收紧:
CREATE VIEW mall.orders_masked AS SELECT order_id, concat('****', substr(phone, 8, 4)) AS phone_masked, amount FROM mall.orders_raw;
兼容层。表重构(拆表、改列名、迁移库)期间,旧表名以视图形态指向新结构,下游 SQL 无感过渡。这个用法让"改表不断服务"成为可能,代价是视图链不能嵌套太深——每层展开都发生在编译期,十层嵌套的视图既难读也会拖慢编译。
视图的使用边界也要直说:它解决"逻辑复用",不解决"重复计算"。同一视图被一百条查询引用,那一百次查询各自把 Join 与过滤算一遍。要共享计算结果,得用物化。
Hive 3 引入物化视图(Materialized View),机制与传统数据库同思路:视图定义加上一份实际存储:
CREATE MATERIALIZED VIEW mall.mv_region_daily AS SELECT dt, region, COUNT(*) AS cnt, SUM(amount) AS amt FROM mall.orders GROUP BY dt, region;
(拼写以实际版本的 CREATE MATERIALIZED VIEW 为准。)
它带来一个编译期新玩法——自动改写:查询"每天每地区的订单量"时,优化器发现这条查询可以从 mv_region_daily 的结果推出来,会自动改写为查物化视图本身,扫描量骤降。EXPLAIN 里你会看到 TableScan 的 alias 变成了物化视图名,这是改写生效的指纹。
代价是维护:底表更新后物化结果过期,要么定时重建,要么依赖增量刷新(版本相关能力,对 ORC 与特定聚合支持最好)。物化视图适合"高频查询加底表缓慢变化"的报表场景,与第 7 章的 LLAP 缓存属于同一战壕的两种武器。
老资料里的"索引操作"章节会教你建 Bitmap 或 Compact 索引:
CREATE INDEX idx_customer ON TABLE mall.orders(customer_id) AS 'COMPACT' WITH DEFERRED REBUILD;
思路是给列建一份"值到文件位置"的辅助表,点查时先查索引缩小扫描范围。听起来合理,实践里三个缺陷叠满:
Hive 3 已经移除了独立的索引语法(ORC 内建索引与物化视图接棒)。看到老集群里的索引表,当作历史遗留处理;新设计一律走"分区加列存加统计"的组合。
| 工具 | 存储成本 | 收益场景 | 维护动作 |
|---|---|---|---|
| 分区 | 目录元数据 | 按时间等维度裁剪扫描 | 分区生命周期管理 |
| 分桶加桶内排序 | 无额外 布局即成本 | 大表连接免 Shuffle 桶抽样 | 灌数纪律与布局体检 |
| 视图 | 零 | 口径复用 权限边界 兼容层 | 底表变更时同步改 |
| 物化视图 | 一份结果存储 | 高频重复查询自动改写 | 定期或增量刷新 |
| 索引 | 辅助表 已退役 | 高选择性点查 | 不再新建 逐步下线 |
决策顺序建议:先问分区能不能解决(最便宜),再问列存与统计够不够(默认组合),再考虑分桶(有明确连接场景才值得),最后才是物化视图(有高频重复查询的证据才建)。每一步都可以用第 3 章的六问清单验证收益是否真的落进了执行计划。