PostgreSQL 物化视图

物化视图是将查询结果作为表保存在数据库中的一种方式,可以像普通表一样查询。通常用于避免反复执行高成本查询,或者保存经常需要使用的数据。

物化视图的优点

提高性能。由于数据已经预先计算,物化视图通常比现场执行连接或汇总查询响应更快。无论原查询多复杂、涉及多少张表,PostgreSQL 都会将结果保存为一张简单的表。

简化查询编写。物化视图可以与其他数据直接连接,从而简化复杂查询。对于经常参与连接的数据,它尤其有用,可以避免在多个不同查询中重复编写相同连接逻辑。

物化视图的缺点

结果是静态的。必须刷新物化视图才能纳入新数据,可以通过 cron 定期执行。但对于银行业务等要求数据精确到当前秒的场景,物化视图并不理想。

占用磁盘空间。物化视图和普通表一样存储在数据库磁盘上,相当于将部分数据保存了两份。

适合使用物化视图的场景

经常需要汇总数据。

不要求实时精确的数据。

电子商务示例

假设一个电商网站使用 PostgreSQL 数据库,包含 products、orders 和 product_orders 三张表。

SELECT * FROM products LIMIT 10;
SELECT * from orders LIMIT 10;
SELECT * from product_orders LIMIT 10;

网站希望显示每件商品最近被购买的次数。营销团队认为,这些信息有助于买家决策。问题是,目前只保存独立的商品和订单记录,没有现成的商品订单总数。我们不希望每位访客打开商品页面时,数据库都重新计算一次。这个数据也不需要绝对实时,足够接近实际即可。

创建物化视图的 SQL

下面的物化视图示例按 SKU 汇总已发货数量,并按 qty 降序排列,使销售最多的 SKU 显示在前面。

CREATE MATERIALIZED VIEW recent_product_sales AS
SELECT p.sku, SUM(po.qty) AS total_quantity
FROM products p
JOIN product_orders po ON p.sku = po.sku
JOIN orders o ON po.order_id = o.order_id
WHERE o.status = 'Shipped'
GROUP BY p.sku
ORDER BY 2 DESC;

创建物化视图后,通常还应为它建立索引,以避免数据库全表扫描。

CREATE INDEX sku_qty ON recent_product_sales(total_quantity);

使用物化视图

可以像查询其他表一样查询这个视图。

SELECT * FROM recent_product_sales;

也可以快速查看销售量最高的 10 件商品,无需另外编写子查询进行求和或排名。

SELECT sku
FROM recent_product_sales
LIMIT 10;

物化视图还可以参与其他查询。下面的查询显示商品 SKU、名称、价格、促销价及近期销量。

SELECT
    p.sku,
    p.name,
    p.price,
    p.sale_price,
    COALESCE(rps.total_quantity, 0) AS recent_sales_quantity
FROM products p
LEFT JOIN recent_product_sales rps ON p.sku = rps.sku;

例如,可以将查询结果用于电商网站的热门商品列表。由于读取的是物化视图,每次有人查看列表时,不必重新执行高成本数据库查询来计算销量。

如果有新数据,需要更新视图,可以执行:

REFRESH MATERIALIZED VIEW recent_product_sales;

这种刷新方式会阻塞物化视图上的并发 SELECT。若要在线刷新,应使用 CONCURRENTLY,但必须先为视图创建唯一索引:

CREATE UNIQUE INDEX recent_product_sales_sku_uidx
  ON recent_product_sales (sku);

REFRESH MATERIALIZED VIEW CONCURRENTLY recent_product_sales;

原文:Materialized Views。作者/来源:Crunchy Data。本文依据所列原文整理为中文,代码、命令与配置示例保留原文。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容