3. 物化视图的创建语法:从基础到实战
创建物化视图,说白了就是给查询结果拍一张「快照」。但怎么拍、拍完要不要马上存、存到哪个表空间,这里头有不少讲究。我刚开始用 Oracle 时,就因为在 WITH DATA 和 WITH NO DATA 之间选错了,导致一个批处理任务跑崩了——嗯,后面我会细说这个坑。
3.1 基础语法:CREATE MATERIALIZED VIEW
先看最核心的骨架:
CREATE MATERIALIZED VIEW view_name
[ TABLESPACE tablespace_name ]
[ BUILD { IMMEDIATE | DEFERRED } ]
[ REFRESH { FAST | COMPLETE | FORCE } ]
[ ON { DEMAND | COMMIT } ]
[ WITH { PRIMARY KEY | ROWID } ]
AS
SELECT ... FROM ... WHERE ...;
别被这么多选项吓到。实际项目中,80% 的场景只需要前三个参数。我个人习惯先写一个最小版本跑通,再慢慢加选项。
核心要点:CREATE MATERIALIZED VIEW 后面必须跟 AS SELECT 子句。没有查询,就没有物化视图。
3.2 WITH DATA 与 WITH NO DATA:要不要马上填充?
这是新手最容易踩坑的地方。两个选项的区别其实很直白:
| 选项 | 行为 | 适用场景 |
|---|---|---|
WITH DATA(默认) |
创建后立即执行查询,把结果写入物化视图 | 数据量小、查询快、需要马上可用 |
WITH NO DATA |
只创建结构,不填充数据,视图处于不可查询状态 | 数据量大、查询慢、想先建结构再择机刷新 |
举个例子:
-- 立即填充(默认行为)
CREATE MATERIALIZED VIEW mv_sales_summary
WITH DATA
AS
SELECT region, SUM(amount) total_sales
FROM sales
GROUP BY region;
-- 只建结构,稍后再填
CREATE MATERIALIZED VIEW mv_sales_summary
WITH NO DATA
AS
SELECT region, SUM(amount) total_sales
FROM sales
GROUP BY region;
-- 稍后手动填充
REFRESH MATERIALIZED VIEW mv_sales_summary;
我曾经踩过的坑:有一次在线上库创建物化视图,忘了加 WITH NO DATA,结果源表有 2 亿行,创建语句跑了 40 分钟还没结束,把临时表空间撑爆了。从那以后,大表场景我必用 WITH NO DATA,先建结构,再在维护窗口用 REFRESH 慢慢填。
为什么会这样?因为 WITH DATA 是同步执行的。如果你的查询涉及多表 JOIN 或聚合,数据量又大,它会把当前会话卡住。你想想看,生产环境里一个 DDL 跑半小时,DBA 不找你喝茶才怪。
3.3 TABLESPACE 指定:把数据放到该放的地方
物化视图本质上是一张表,它需要物理存储空间。TABLESPACE 就是告诉数据库:把这张「快照表」放在哪个表空间里。
我建议遵循两个原则:
- 读写分离:物化视图放只读表空间,源表放读写表空间
- 性能隔离:高频访问的物化视图放 SSD 表空间,低频的放 HDD 表空间
-- 指定表空间
CREATE MATERIALIZED VIEW mv_orders_monthly
TABLESPACE ts_mv_data
WITH DATA
AS
SELECT DATE_TRUNC('month', order_date) AS month,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
GROUP BY DATE_TRUNC('month', order_date);
小技巧:如果不指定 TABLESPACE,物化视图会创建在用户的默认表空间里。我个人习惯在创建语句里显式指定,避免后续迁移的麻烦。
3.4 完整语法结构图
下面这张图把创建语法的核心流程串起来了,方便你对照理解:
3.5 实战建议:三种场景怎么选
根据我这些年的经验,不同场景的创建策略可以总结成一张表:
| 场景 | 推荐语法 | 理由 |
|---|---|---|
| 小表(< 10万行) | WITH DATA + 默认表空间 |
创建快,直接可用,省事 |
| 大表(> 100万行) | WITH NO DATA + 指定表空间 |
避免长时间阻塞,存储可规划 |
| 生产环境首次部署 | WITH NO DATA + 专用表空间 |
先验证结构,再择机填充,风险最低 |
我的习惯:不管数据量大小,我写创建语句时都会把 TABLESPACE 带上。哪怕暂时用默认表空间,也显式写出来——这样以后查 DDL 时一眼就能看到存储位置,不用去猜。