【问题标题】:Check last refreshed time for materialized view检查物化视图的上次刷新时间
【发布时间】:2014-02-05 14:46:45
【问题描述】:

我有一个名为price_changes 的具体化视图,用于一些报告。我还有一个 cron 工作,用refresh materialized view price_changes 刷新物化视图。一切都很好。

我想向查看报告的用户发送一条消息“数据从 X 开始是最新的”。我可以在 cron 运行时将它存储在某个地方,但是 postgres 是否已经将这个元数据存储在某个地方?

【问题讨论】:

标签: postgresql materialized-views


【解决方案1】:

如果您可以访问服务器,我认为@richyen 解决方案是最好的。

如果您不这样做,您必须以某种方式手动将上次刷新日期存储为元数据。一些选项是:

  • 作为@thames 响应中的列,主要缺点是列的额外使用存储(重复与行的 MV 一样多次)以及@smudge 所述的大表中的刷新问题。

  • 在自定义表格中。主要缺点是您必须确保所有刷新都包括表更新。

-- Create table
CREATE TABLE pg_matviews_last_refreshed (
  matviewowner NAME NOT NULL,
  matviewname NAME NOT NULL,
  schemaname NAME NOT NULL,
  last_refreshed TIMESTAMP NOT NULL,
  CONSTRAINT pk UNIQUE (matviewowner, matviewname, schemaname)
)

CREATE VIEW pg_matviews_extra AS
SELECT * 
FROM pg_matviews
NATURAL JOIN pg_matviews_last_refreshed

-- Set initial values
INSERT INTO pg_matviews_last_refreshed (
  matviewowner,
  matviewname,
  schemaname,
  last_refreshed
)
SELECT 
  matviewowner,
  matviewname,
  schemaname,
  CURRENT_TIMESTAMP
FROM pg_matviews;

-- Consult dates
SELECT * FROM pg_matviews_extra

-- Refresh 
BEGIN;
REFRESH MATERIALIZED VIEW CONCURRENTLY my_materialized_view;

-- Insert update date into last_refreshed table. Of course, if 
-- more complex permissions are into place, the query becomes more
-- complex to discover owner, schema, etc.
INSERT INTO pg_matviews_last_refreshed (matviewname, matviewowner, schemaname, last_refreshed)
SELECT matviewname, matviewowner, schemaname, CURRENT_TIMESTAMP
FROM pg_matviews
WHERE matviewname='my_materialized_view'
ON CONFLICT (matviewname, matviewowner, schemaname)
DO UPDATE SET last_refreshed=EXCLUDED.last_refreshed;
COMMIT;
  • 与使用专用表存储上次刷新日期类似,您可以将该信息隐式存储在 MV 注释中:
-- Refresh operation
BEGIN;
REFRESH MATERIALIZED VIEW CONCURRENTLY my_materialized_view;
-- This statement can be wrapped into a function to allow using CURRENT_TIMESTAMP
COMMENT ON MATERIALIZED VIEW my_materialized_view IS '{"last_refreshed": "2021-07-07T09:30:59Z"}'
COMMIT;


-- Retrieve refresh date
SELECT (pg_catalog.obj_description('my_materialized_view'::regclass, 'pg_class')::json->>'last_refreshed')::timestamp;

【讨论】:

  • PD:我认为可以在物化视图中注册触发器。我想知道刷新MV时是否可以将元数据更新操作注册为触发器
【解决方案2】:

由于物化视图是存储在磁盘上的数据段,因此它们将在文件系统中具有相应的文件。当您调用REFRESH MATERIALIZED VIEW 时,磁盘上的数据会以新文件名重新创建。因此,您可以通过在pg_class 中与relfilenode 交叉引用来查找视图的修改/创建时间戳:

[user@server /]# psql -c "create materialized view myview as select aid from pgbench_accounts where aid < 100"
SELECT 99
[user@server /]# psql -c "select relfilenode from pg_class where relname = 'myview'"
 relfilenode 
-------------
       16445
(1 row)

[user@server /]# ls -l /var/lib/edb/as12/data/base/15369/16445
-rw------- 1 enterprisedb enterprisedb 8192 Jun 14 23:28 /var/lib/edb/as12/data/base/15369/16445
[user@server /]# date
Mon Jun 14 23:29:16 UTC 2021
[user@server /]# psql -c "refresh materialized view myview"
REFRESH MATERIALIZED VIEW
[user@server /]# psql -c "select relfilenode from pg_class where relname = 'myview'"
 relfilenode 
-------------
       16449
(1 row)

[user@server /]# ls -l /var/lib/edb/as12/data/base/15369/16449
-rw------- 1 enterprisedb enterprisedb 8192 Jun 14 23:29 /var/lib/edb/as12/data/base/15369/16449
[user@server /]# 

【讨论】:

  • 哇,7 年后的答案真是太棒了!
【解决方案3】:

我认为从 9.3.4 开始,系统中没有任何内置功能可以提供此功能。当我需要提供上次刷新的日期时,我会在物化视图中的选择查询中添加一个名为“last_refresh”的列,因为物化视图中的数据在刷新之前不会改变。

出于安全原因,我也更喜欢这种方式,因为如果信息存储在系统表中,您可能不想让 sql 用户访问系统表。

根据您是否需要时间,您可以使用以下任一方式:

  1. CURRENT_DATE
  2. now()

只是日期:

CREATE MATERIALIZED VIEW mv_address AS 
SELECT *, CURRENT_DATE AS last_refresh FROM address;

日期和时间:

CREATE MATERIALIZED VIEW mv_address AS 
SELECT *, now() AS last_refresh FROM address;

2017 年 2 月 17 日更新:

PostgreSQL 版本 9.4+ 现在包括 CONCURRENTLY 选项。如果您使用 REFRESH MATERIALIZED VIEW CONCURRENTLY 选项,请注意 cmets 中 @Smudge 指示的内容。对于大型且频繁更新的数据集,这实际上只是一个问题。如果您的数据集很小或不经常更新,那么您应该没问题。

【讨论】:

  • 注意:这种方法将导致REFRESH MATERIALIZED VIEW CONCURRENTLY 每次更新每一行。对于不经常刷新的较小数据集,这不会是一个大问题,但对于大量数据和/或频繁更新,DELETEINSERT 的速率可能会超过 autovacuum 守护进程对 VACUUM 表的能力,导致基本查询性能急剧下降。
  • 从现实世界的经验中说 - Smudge 所指的问题很容易滚雪球,直到您的数据库花费 100% 的时间处理大量死元组并且在您 DROP 并重新创建之前无法恢复物化视图。使用此解决方案时要格外小心。
猜你喜欢
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
  • 2019-01-10
  • 2011-07-09
  • 2013-12-04
  • 2020-01-31
  • 2021-10-14
  • 2014-07-11
相关资源
最近更新 更多