← 返回题目列表

PostgreSQL 物化视图和普通视图有什么区别?适合什么场景?

高频 中等 第 13 / 31 题 更新于 2026/07/29
PostgreSQL物化视图视图查询优化

简化版

普通视图保存的是查询定义,每次访问都会执行底层查询;物化视图保存的是查询结果,读取快但数据不会自动实时更新,需要手动或定时刷新。物化视图适合复杂报表、读多写少、允许一定延迟的统计场景。

详细版

普通视图像一个 SQL 别名,主要用于封装查询逻辑和权限边界。物化视图会把结果落盘,因此可以建索引,查询性能更好。

区别:

  • 普通视图不存结果,实时但可能慢。
  • 物化视图存结果,快但有延迟。
  • 物化视图需要 refresh materialized view
  • 并发刷新通常需要唯一索引支持。
  • 不适合强实时数据。

面试回答要强调“用空间和刷新成本换查询速度”,并说明刷新策略和一致性延迟。

完整版教学

一、普通视图保存的是查询定义

普通视图本质是一段命名 SQL。查询视图时,数据库会把视图定义展开到实际查询中。它不保存结果,所以数据实时性好。

create view active_users as
select id, name
from users
where deleted_at is null;

普通视图适合封装复杂 SQL、限制字段暴露、统一业务口径。但如果底层查询很重,每次访问都会付出计算成本。

记忆钩子:普通视图是“查询模板”,物化视图是“缓存结果表”。

二、物化视图保存的是查询结果

物化视图会把查询结果存下来,访问时像查表一样读取已计算结果。

create materialized view daily_sales as
select date(created_at) as day, sum(amount) as total_amount
from orders
group by date(created_at);

如果订单表有 1 亿行,每次实时报表都聚合会很慢。物化视图提前算好结果,报表查询可以非常快。

代价是数据有延迟。底层订单新增后,物化视图不会自动变化,必须刷新。

三、刷新策略决定可用性

刷新物化视图常用:

refresh materialized view daily_sales;

普通刷新可能阻塞读取。PostgreSQL 支持并发刷新:

refresh materialized view concurrently daily_sales;

并发刷新通常要求物化视图上有唯一索引。它能降低读阻塞,但刷新仍然消耗 CPU、IO 和临时空间。

四、物化视图可以建索引

因为物化视图有真实存储,所以可以为它建索引。这是它相比普通视图的重要优势。

create unique index uk_daily_sales_day on daily_sales(day);

索引能让报表按日期查询更快,也满足并发刷新要求。需要注意的是,刷新后索引也要维护,物化视图越大,刷新成本越高。

五、物化视图适合读多写少的汇总查询

物化视图典型场景是复杂统计、数据看板、离线报表、权限范围固定的聚合结果。它不适合强实时交易查询。

场景是否适合
每日销售汇总适合
大屏分钟级统计视延迟要求而定
下单后立即查库存不适合
复杂 join 后的只读列表可能适合

判断标准是:用户能不能接受刷新延迟,以及刷新成本是否低于实时查询成本。

六、物化视图不是自动增量维护

很多人误以为物化视图像缓存一样自动更新。PostgreSQL 原生物化视图通常需要全量刷新,不是自动增量。

如果数据量很大,全量刷新可能很重。可以考虑按日期分层汇总、用普通汇总表自己增量维护,或借助 ETL/任务系统。

订单明细 -> 小时汇总表 -> 日汇总表 -> 报表查询

物化视图是一种工具,不是所有统计问题的终点。

七、常见误区与追问

  • 误区:普通视图能提升查询性能。 普通视图主要封装 SQL,不保存结果,不一定更快。
  • 误区:物化视图会自动实时更新。 它需要手动或定时刷新,存在数据延迟。
  • 误区:物化视图适合所有报表。 刷新成本过高或实时性要求强时不适合。
  • 追问:并发刷新需要什么条件? 通常需要物化视图有唯一索引。
  • 追问:物化视图和汇总表怎么选? 简单全量刷新用物化视图;复杂增量维护可用自建汇总表。
  • 追问:刷新会不会阻塞查询? 普通刷新可能阻塞,并发刷新能降低影响但成本仍在。

八、面试中可以这样落地

如果订单报表每天访问很多次,但允许 5 分钟延迟,可以建物化视图并由定时任务刷新。

create materialized view mv_order_day as
select date(created_at) day, count(*) cnt, sum(amount) amount
from orders
group by date(created_at);

create unique index uk_mv_order_day on mv_order_day(day);

然后用任务执行 refresh materialized view concurrently mv_order_day。如果数据量继续增大,再演进到增量汇总表。

九、加强记忆

普通视图是 SQL 封装,物化视图是落盘结果。物化视图用刷新成本和存储空间换读取速度,适合读多写少且允许延迟的统计场景。面试时记得讲刷新、索引、并发刷新和数据延迟。