如何解决刷新物化视图非同时以“没有剩余空间”错误结束
这里有一个类似标题的问题:https://dba.stackexchange.com/questions/271237/postgresql-refreshing-materialized-view-fails-with-no-space-left-on-device-an
但是,我遇到的症状似乎有所不同:
- 在 Spring Boot 应用程序中使用
REFRESH MATERIALIZED VIEW mySchema.myView
刷新时,只要设备上有空间,Postgressql 就会写入 tmp 文件,目前为 128GB。 - 当通过任何 sql 控制台(如 PgAdmin)执行相同的刷新查询时,一切都很好。视图会在几秒钟内刷新,写入的 tmp 数据不超过 100mb。
我们目前使用 Postgresql 13.3,但 11.11 表现出相同的行为。
使用的 JDBC 驱动程序版本:
- 42.2.14
- 42.2.18
所以,我不知道这是从哪里来的。由于使用某些 sql 控制台进行刷新可以按预期工作,因此我认为优化查询不是第一件事。记录应用程序生成的所有 sql 也没有发现任何可疑之处。
如果有帮助,这里是视图的查询。这取决于其他视图 (*_c
),它们都可以正常刷新:
WITH RECURSIVE chapters (code_id,chapter_id) AS (
SELECT Ziffer.tael_id AS code_id,Ziffer.tael_id as chapter_id
FROM tael_c AS Ziffer
INNER JOIN tael_c AS Tariff ON Ziffer.tael_idt = Tariff.tael_id AND Ziffer.tael_typ = 25 AND Ziffer.validfrom < COALESCE(Tariff.invalidfrom,DATE '9999-12-31') AND Tariff.validfrom < COALESCE(Ziffer.invalidfrom,DATE '9999-12-31')
UNION
SELECT chapters.code_id,tete_c.tael_idp as chapter_id
FROM chapters
INNER JOIN tete_c ON chapters.chapter_id = tete_c.tael_idc
INNER JOIN tael_c ON tete_c.tael_idc = tael_c.tael_id AND tael_c.tael_typ IN (3,25)
)
SELECT Ziffer.tael_id,GREATEST(Ziffer.wsid,Kapitel.wsid,Conn.wsid,InExTael.wsid,InEx.wsid) AS wsid,GREATEST(Ziffer.validfrom,Kapitel.validfrom,Conn.validfrom,InExTael.validfrom,InEx.validfrom) AS validfrom,LEAST(Ziffer.invalidfrom,Kapitel.invalidfrom,Conn.invalidfrom,InExTael.invalidfrom,InEx.invalidfrom) AS invalidfrom,string_agg(InEx.txtx_txt,',') FILTER (WHERE InExTael.tael_typ = 40) AS Incl,') FILTER (WHERE InExTael.tael_typ = 46) AS Excl
FROM chapters
INNER JOIN tael_c AS Ziffer ON Ziffer.tael_id = chapters.code_id
INNER JOIN tael_c AS Kapitel ON chapters.chapter_id = Kapitel.tael_id AND Kapitel.validfrom < COALESCE(Ziffer.invalidfrom,DATE '9999-12-31') AND Ziffer.validfrom < COALESCE(Kapitel.invalidfrom,DATE '9999-12-31')
INNER JOIN tete_c AS Conn ON Kapitel.tael_id = Conn.tael_idp AND Conn.validfrom < COALESCE(LEAST(Ziffer.invalidfrom,Kapitel.invalidfrom),DATE '9999-12-31') AND GREATEST(Ziffer.validfrom,Kapitel.validfrom) < COALESCE(Conn.invalidfrom,DATE '9999-12-31')
INNER JOIN tael_c AS InExTael ON Conn.tael_idc = InExTael.tael_id AND InExTael.tael_typ IN (40,46) AND InExTael.validfrom < COALESCE(LEAST(Ziffer.invalidfrom,Conn.invalidfrom),Conn.validfrom) < COALESCE(InExTael.invalidfrom,DATE '9999-12-31')
INNER JOIN txtx_c AS InEx ON InEx.tael_id = InExTael.tael_id AND InEx.validfrom < COALESCE(LEAST(Ziffer.invalidfrom,InExTael.invalidfrom),InExTael.validfrom) < COALESCE(InEx.invalidfrom,DATE '9999-12-31')
GROUP BY 1,2,3,4
关于如何调试这个有什么想法吗?
更新
刷新是 Spring Boot 应用程序中批处理作业的一部分。这是一个更大的项目的一部分,其中一切都是新的和闪亮的。应用程序和 Postgresql 将部署在 OpenShift 中。只是为了添加更多上下文。
同样的行为发生在本地安装的 Postgresql(13.2,Windows)以及容器化版本(13.3,Linux)中。
原始开发人员将刷新逻辑放在@AfterStep 侦听器中。我现在已将其移至单独的 Spring Batch tasklet,以便将其置于单独的事务上下文中(请参阅 In Spring Batch,can I insert data in a beforeStep implementation)。此外,我们将 WITH 部分分成了它自己的视图。还是一样,控制台正常,应用程序不正常。
我会检查@borchvm 链接中的任何内容是否有帮助。 而且,我有一个旧版本的视图,它产生相同的数据,但速度要慢得多。所以,至少,我还有一些东西可以坚持。另外,像口袋一样了解数据结构的原始开发人员会尝试寻找另一种更有效的方法。
解决方法
您没有足够的可用临时空间。我猜表有太多的数据。尝试更有效地重写您的选择。 或者最糟糕的解决方案是将您的代码分开在不同的物化视图中,然后将它们合并到一个单一的物化视图中 :)
psql> SELECT datname,temp_files AS "Temporary files",temp_bytes AS "Size of temporary files" FROM pg_stat_database ;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。