如果两个进程同时尝试刷新实体化视图会发生什么?

fff*_*abs 15 postgresql materialized-view plpgsql

根据文档:

CONCURRENTLY 刷新物化视图而不锁定物化视图上的并发选择。(……)

... 其他内容 ...

即使使用此选项,一次也只能针对任何 一个物化视图运行一个 REFRESH

一个函数可以检查 MATERIALIZED VIEW 的上次刷新时间,如果超过 60 秒,它会刷新它。

但是,如果我尝试同时从两个单独的进程刷新物化视图会发生什么?他们会排队还是会引发错误?

有没有办法检测何时刷新 MATERIALIZED VIEW 从​​而避免触摸它?

目前,我已经在刷新(设置refreshingtrue)之前填充表记录,然后false在过程完成时将其设置为。

EXECUTE 'INSERT INTO refresh_status (last_update, refreshing) 
         VALUES (clock_timestamp(), true) RETURNING id') INTO refresh_id;
EXECUTE 'REFRESH MATERIALIZED VIEW CONCURRENTLY my_mat_view';
EXECUTE 'UPDATE refresh_status SET refreshing=false WHERE id=$1' USING refresh_id;
Run Code Online (Sandbox Code Playgroud)

然后,每当我调用此过程时,我都会检查最新的last_update及其refreshing值。如果refreshing为 true,则不要尝试刷新物化视图。

EXECUTE 'SELECT 
           extract(epoch FROM now() - (last_update))::integer, 
           refreshing
         FROM refresh_status
         ORDER BY last_update DESC
         LIMIT 1' INTO update_seconds_ago, refreshing;

IF(updated_seconds_ago > 60 AND refreshing = FALSE) THEN
  -- the refresh block above
END IF;
Run Code Online (Sandbox Code Playgroud)

但是,我不确定刷新标志是否正在同步更新(我的意思是,它确实在等待刷新实际完成)

这种方法是合理的还是我在这里遗漏了什么?

mus*_*cio 16

正如提到的这个答案,“REFRESH MATERIALIZED VIEW CONCURRENTLY需要一个EXCLUSIVE锁定”在桌子上。根据文档的 crumb trail我们可以读到,EXCLUSIVE表上的锁“只允许并发ACCESS SHARE锁,即只有从表中读取才能继续”。在同一段中,我们可以看到“EXCLUSIVE与...冲突EXCLUSIVE”,这意味着另一个REFRESH MATERIALIZED VIEW CONCURRENTLY请求相同EXCLUSIVE锁的语句将不得不等待,直到较早的EXCLUSIVE锁被释放。

如果您想避免在未定义的时间内等待此锁,您可能需要将会话变量lock_timeout设置为一个合理的值。


RDF*_*ozz 5

正如Mustaccio所指出的,这个问题与Postgres Refresh Materialized View Locks有很大的重叠。

然而,虽然该问题的已接受答案有一个回答该问题的链接,但该问题的答案并未直接包含在该问题中。

因此,具体来说:根据有关显式锁定的 PostgreSQL 手册页(链接到当前版本页面,对于 PostGres 10),REFRESH MATERIALIZED VIEW CONCURRENTLY需要EXCLUSIVE锁定。该EXCLUSIVE锁似乎阻止了所有其他锁,除了 ACCESS SHARE- 包括其他EXCLUSIVE锁。

因此,对同一视图的第二个REFRESH MATERIALIZED VIEW CONCURRENTLY请求将等待第一个请求获得的锁被释放。