这是我的老问题多个并发“REFRESH MATERIALIZED VIEW”的延续:如何管理?
现在,在最初更加理论化之后,不幸的是,我正在与真实的事物作斗争:)
我有一个发送许多请求的程序,最后刷新一个物化视图。不幸的是,有时,两个并发作业请求重叠CREATE MATERIALIZED VIEW milestones_files
(视图很大并且需要几分钟才能刷新),所以最新的作业失败(显然),这会取消整个事务(这很糟糕,因为一些数据库更新也被删除了)。
这是发生错误时的日志(为简洁起见,没有所有 SQL 行):
2022-03-22 11:17:37.685 UTC [29004] storiq@storiqone ERREUR: Bloquage mortel détecté
2022-03-22 11:17:37.685 UTC [29004] storiq@storiqone DÉTAIL: Le processus 29004 attend AccessExclusiveLock sur relation 181019 de la base de données 19044 ; bloqué par le processus 29174.
2022-03-22 11:17:37.685 UTC [29004] storiq@storiqone ASTUCE : Voir les journaux applicatifs du serveur pour les détails sur la requête.
2022-03-22 11:17:37.685 UTC [29004] storiq@storiqone INSTRUCTION : CREATE MATERIALIZED VIEW milestones_files_29000 AS SELECT sa.id AS archive,
2022-03-22 11:17:37.691 UTC [29243] storiq@storiqone ERREUR: could not open relation with OID 181019
2022-03-22 11:17:37.691 UTC [29243] storiq@storiqone INSTRUCTION : SELECT REGEXP_REPLACE(pg_catalog.pg_get_ruledef(r.oid, TRUE), '^.*DO INSTEAD (SELECT.*);$', '\1') FROM pg_catalog.pg_rewrite r WHERE r.ev_class = ( SELECT oid FROM pg_class WHERE relname = 'milestones_files')
2022-03-22 11:17:37.693 UTC [29243] storiq@storiqone ERREUR: la transaction est annulée, les commandes sont ignorées jusqu'à la fin du bloc
2022-03-22 11:17:37.693 UTC [29243] storiq@storiqone INSTRUCTION : UPDATE archivetoarchivemirror SET lastupdate = NOW(), jobrun = $1 WHERE archive = $2 OR jobrun = $1
2022-03-22 11:17:37.696 UTC [29243] storiq@storiqone ERREUR: l'instruction préparée « update_archivemirrors » n'existe pas
2022-03-22 11:17:39.510 UTC [29004] storiq@storiqone ERREUR: la transaction est annulée, les commandes sont ignorées jusqu'à la fin du bloc
2022-03-22 11:17:39.510 UTC [29004] storiq@storiqone INSTRUCTION : UPDATE archivetoarchivemirror SET lastupdate = NOW(), jobrun = $1 WHERE archive = $2 OR jobrun = $1
2022-03-22 11:17:39.510 UTC [29004] storiq@storiqone ERREUR: l'instruction préparée « update_archivemirrors » n'existe pas
当然我可以简单地将CREATE MATERIALIZED VIEW
命令放在主事务之外,但是最新的刷新仍然会失败,因此视图不会反映数据库中的最新更改,这仍然是一个(不太严重的)问题。
理想情况下,我希望最新的刷新优先,但不会使已经在另一个进程中运行的事务失败(如果我在检查锁后简单地杀死另一个进程,就会出现这种情况,根据Kill concurrent materialized view refresh PID) .
从文档来看,添加该选项似乎CONCURRENTLY
也不能解决我的问题(这与并发 SELECT 无关)。
欢迎任何建议。当然,我可以尝试实施我在旧问题中提出的解决方案,尽管考虑到级联查询和事务以及庞大的数据库,它会特别复杂......
您可以为此编写一个过程:
当然也可以使用客户端代码编写相同的内容。这可能会锁定,但绝不会死锁,并且您可以确定实体化视图将在过程完成时反映插入。