触发函数刷新 Postgres 物化视图并捕获刷新结束时间?

Trigger function to refresh Postgres materialized view and capture refresh end time?

我正在尝试在我们的 Postgres 数据库中构建一个摘要 table,其中包含有关何时刷新各种物化视图的信息。我也希望这个 table 触发实际刷新。

table 所需的格式如下,称其为 mv_refresh_monitor:

view_name refresh_time_start refresh_time_end
view_one 2022-02-01 22:10:59.234567 2022-02-01 22:11:59.234567

table 显示 view_one 上次刷新时间为 2 月 1 日深夜,刷新用时 1 分钟完成。

我想做的是通过更新 refresh_time_start 字段来触发物化刷新;这样做会触发 view_name 字段中的实体化视图刷新,然后还会更新同一行的 refresh_time_end 字段以捕获刷新完成的时间。

我当前的实现使用一个函数(更新监视器 table)、一个触发器函数(刷新视图和调用函数)以及监视器上的触发器 table调用触发函数。这仅适用于单个实体化视图:

CREATE OR REPLACE FUNCTION "ingested_digital_spend"."timestamp_refresh_end"()
  RETURNS "pg_catalog"."void" AS $BODY$
        UPDATE schema.mv_refresh_monitor SET refresh_time_end = CURRENT_TIMESTAMP AT TIME ZONE 'America/Los_Angeles';
$BODY$
  LANGUAGE SQL;

CREATE OR REPLACE FUNCTION "schema"."refresh_materialized_view"()
  RETURNS "pg_catalog"."trigger" AS $BODY$
BEGIN
IF NEW.view_name = 'view_one' AND NEW.refresh_time_start IS DISTINCT FROM OLD.refresh_time_start THEN
REFRESH MATERIALIZED VIEW schema.view_one;
        PERFORM timestamp_refresh_end();
END IF;
RETURN NULL;
END;
$BODY$
  LANGUAGE plpgsql;

CREATE TRIGGER "refresh_mv" AFTER UPDATE ON "schema"."mv_refresh_monitor"
FOR EACH ROW
EXECUTE PROCEDURE "schema"."refresh_materialized_view"();

这几乎可以工作,但我正在尝试改进/修复三件事:

  1. 将其参数化,这样我就不必在每次向模式添加新的实体化视图时都在触发器函数中编写新的 IF THEN END IF 子句。
    • 这似乎不应该很难,我只是还没有找到参数化 PL/pgSQL 函数的正确方法。
  2. 目前 refresh_time_startrefresh_time_end 中记录的时间是相同的,尽管刷新操作本身需要 80 秒。我不确定如何确定 CURRENT_TIMESTAMP 操作的范围,以便它们在最初调用触发器函数时不会评估为相同的时间戳。
    • 这感觉应该是可能的,但我不太确定。
  3. 如果可能的话,我希望实际刷新发生在“后台”。也就是说,更新立即完成并释放正在执行更新的会话。现在监视器 table 上的事务直到视图刷新事务本身完成后才完成,因此客户端会话挂起直到刷新完成。
    • 这可能是不可能的。

对于接近这三个要求有什么建议或解决方案吗?

我认为你在 trigger/function 中过多地推动了这个错误的方式。我会选择:

  1. 您向其提供视图名称和开始名称的函数。它执行 REFRESH MATERIALIZED VIEW some_view> 并使用信息更新 mv_refresh_monitor。有关如何对其进行参数化的信息,请参阅 Dynamic Queries

  2. 有关 CURRENT_TIMESTAMP 问题,请参阅 Current date/timeCURRENT_TIMESTAMP 按照设计捕获事务开始时的时间戳,并且不会在事务中更改。您正在寻找 transaction_timestamp()/statement_timestamp().

  3. 如果您不将 REFRESH MATERIALIZED VIEWUPDATE 联系起来,您就可以解决这个问题。