检查物化视图的上次刷新时间

时间:2014-01-16 15:35:47

标签: postgresql materialized-views

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

我想让用户在报告中看到一条消息“数据从X开始是新鲜的”。当cron运行时,我可以将它存储在某个地方,但是postgres是否已经在某处存储了这些元数据?

3 个答案:

答案 0 :(得分:12)

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

出于安全原因,我也更喜欢这个,因为如果信息存储在那里,你可能不想让sql用户访问系统表。

根据您是否需要时间,您可以使用:

  1. CURRENT_DATE
  2. now()
  3. 刚出日期:

    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-02-17:

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

答案 1 :(得分:1)

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

[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 /]# 

答案 2 :(得分:0)

如果您可以访问服务器,我认为@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;