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