如果两个过程尝试同时同时刷新材料视图,会发生什么?


13

根据文档:

同步刷新实例化视图,而不会锁定实例化视图上的并发选择。(...)

...其他内容...

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

一个功能,可以检查上次刷新时间以进行材料视图,如果超过60秒,它将刷新它。

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

有没有一种方法可以检测何时刷新了材料视图,因此避免触摸它?

目前,我在刷新之前将表记录填充(设置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;

然后,每当我调用此过程时,我都会检查最新过程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;

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

这种方法合理吗?还是我在这里遗漏了一些东西?

Answers:


13

正如提到的这个答案,“ REFRESH MATERIALIZED VIEW CONCURRENTLY需要一个EXCLUSIVE锁定”在桌子上。遵循文档的痕迹,我们可以看到EXCLUSIVE表上的锁“仅允许并发ACCESS SHARE锁,即,仅可以从表中进行读取”。在同一段中,我们可以看到“ EXCLUSIVE与...冲突EXCLUSIVE”,这意味着另一个REFRESH MATERIALIZED VIEW CONCURRENTLY请求相同EXCLUSIVE锁的语句将不得不等待,直到EXCLUSIVE释放了较早的锁。

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


PS:您认为保留此辅助表来告知并发(无双关)尝试是MAT VIEW繁忙,因此即使看起来需要刷新也应单独放置吗?
ffflabs

这只是一个见解;如果您认为这有帮助,那么您当然可以保持逻辑。但是请注意,您的功能受比赛条件的影响,因此并非100%可靠。
mustaccio

您认为先检查pg_locks然后看看是否有一个引用mat视图是可行的吗?
ffflabs

同样,可能出现竞争情况:检查pg_locks和开始刷新之间有可能会被锁住。解决锁冲突的一种正确方法是设置超时并处理错误。
mustaccio

3

正如mustaccio所指出的,此问题与Postgres刷新物化视图锁显着重叠。

但是,尽管该问题的公认答案具有一个可以回答该问题的链接,但该问题的答案并不直接包含在该问题中。

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

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


谢谢。我仍然将@mustaccio的答案标记为已接受,因为他编辑了文字以使其更具体地针对我的问题。
ffflabs

0

多亏了mustaccioRDFozz的回答,我终于明白,REFRESH ... CONCURRENTLY使用独占锁是PostgreSQL文档说的原因:

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

我担心这意味着任何同时进行刷新的尝试都会引发错误,但是根据他们的回答,不会涉及任何特殊错误。只是锁的问题会导致同时尝试排队。因此,文档可以解释为:

在此操作期间获取的锁定将阻止除从MATERIALIZED VIEW中读取以外的任何操作。在REFRESH ... CONCURRENTLY正在运行时,进一步尝试刷新实例化视图将排队,直到释放第一个锁为止。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.