物化视图是“快照副本”,普通视图是“实时投影”;CREATE MATERIALIZED VIEW 立即执行并存储结果,需显式 REFRESH,而 CREATE VIEW 仅保存逻辑、无需刷新;默认 REFRESH 会阻塞查询,CONCURRENTLY 刷新可避免阻塞但要求唯一索引。

视图是“实时投影”,物化视图是“快照副本”——选错类型,要么查得慢,要么数据旧,甚至锁表失败。
CREATE VIEW 和 CREATE MATERIALIZED VIEW 语法差异
两者创建语句只差一个关键词,但底层行为完全不同:CREATE VIEW 仅保存查询逻辑;CREATE MATERIALIZED VIEW 立即执行查询并把结果写入磁盘。PostgreSQL 要求物化视图必须显式刷新,而普通视图根本不存在“刷新”概念。
-
CREATE VIEW v_recent_orders AS SELECT * FROM orders WHERE created_at > NOW() - INTERVAL '7 days';—— 每次SELECT * FROM v_recent_orders都重跑 WHERE 条件 -
CREATE MATERIALIZED VIEW mv_recent_orders AS SELECT * FROM orders WHERE created_at > NOW() - INTERVAL '7 days';—— 创建时就存好结果,后续查的是这张物理表
REFRESH MATERIALIZED VIEW 会阻塞查询吗
默认会。PostgreSQL 的 REFRESH MATERIALIZED VIEW 是原子替换:先删旧数据、再插入新数据,期间新查询会被阻塞,直到刷新完成。这是最常见卡顿源头。
- 加
CONCURRENTLY可避免阻塞(REFRESH MATERIALIZED VIEW CONCURRENTLY mv_recent_orders),但前提是该物化视图已有唯一索引(如主键或UNIQUE列) - 没有唯一索引时强行加
CONCURRENTLY会报错:ERROR: cannot refresh materialized view "mv_recent_orders" concurrently - Oracle 或 SQL Server 的类似操作可能换名(如
DBMS_MVIEW.REFRESH),但锁行为逻辑相似
物化视图能建索引,普通视图不能
普通视图本质是 SQL 文本,数据库无法在其上建索引;物化视图是一张真实存在的表,支持 CREATE INDEX,这对加速 WHERE 或 JOIN 查询至关重要。
- 例如:
CREATE INDEX idx_mv_region ON mv_recent_orders (region);能让按地区过滤快很多 - 但注意:索引本身也占空间、拖慢刷新速度——如果物化视图每天只查 2 次,却每小时刷新 + 建索引,纯属浪费
- 某些数据库(如 ClickHouse)对普通视图做了谓词下推优化,反而比固化了过滤条件的物化视图更灵活
物化视图不可更新,普通视图有时可以
普通视图只要满足简单条件(单表、无聚合、无 DISTINCT),就能直接 INSERT/UPDATE/DELETE,操作最终落在基表上;物化视图一律只读,任何写操作都会报错。
-
UPDATE v_recent_orders SET status = 'shipped' WHERE id = 123;→ 成功(若视图定义允许) -
UPDATE mv_recent_orders SET status = 'shipped' WHERE id = 123;→ 报错:ERROR: cannot update a materialized view - 想“更新”物化视图?只能
REFRESH,且刷新后所有变更都来自基表,不是你手动改的
真正容易被忽略的点是:物化视图不是“性能银弹”。它把计算成本从查询时挪到刷新时,如果基表很小、查询很轻(比如 SELECT * FROM users WHERE id = 123),用普通视图走索引反而更快;而频繁刷新大结果集,可能压垮 I/O 或锁住关键报表查询。选型前先问自己:这数据多久变一次?查询频次多高?能容忍几秒延迟?

















