我有一个名为price_changes
的物化视图用于某些报告。我还有一个cron作业用refresh materialized view price_changes
刷新物化视图。一切都很好。
我想让用户在报告中看到一条消息“数据从X开始是新鲜的”。当cron运行时,我可以将它存储在某个地方,但是postgres是否已经在某处存储了这些元数据?
答案 0 :(得分:12)
我认为系统中没有内置任何内容,从9.3.4开始提供此功能。当我需要提供上次刷新的日期时,我在物化视图中的select查询中添加了一个名为“last_refresh”的列,因为物化视图中的数据在刷新之前不会更改。
出于安全原因,我也更喜欢这个,因为如果信息存储在那里,你可能不想让sql用户访问系统表。
根据您是否需要时间,您可以使用:
CURRENT_DATE
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-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;
-- 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;