我能否每1-2分钟运行一次PostgreSQL的Vacuum?

4
我正在考虑为即将到来的项目选择各种MVCC-capable数据库,而PostgreSQL引起了我的注意。
我的程序要求大致如下:
1. 从当前版本的数据库中读取一些信息,在一个或多个事务中修改80-90%的数据,并将其写回(想象一下更新康威生命游戏中的网格,需要旧网格和新网格的状态)。 2. 提交后等待1-2分钟。在此期间,客户端可以针对新数据发出读取请求。 3. 重复进行。
数据库将被限制在2-4GB左右。
约90%的更改是对现有对象的更新,约5%是新对象,另外约5%是删除对象。
那么我的问题是,我能否合理地运行一个纯粹的VACUUM命令作为步骤1.5,每1-2分钟一次,并让PostgreSQL能够跟上每次可能进行的2-3+GB的更改?

5
您可能不需要手动运行。调整特定表的自动清理设置应该足够了。但只有在删除或插入大量行时,真正需要清理。更新不需要如此积极的清理。 - user330315
我的理解是每次更新都会生成一个新的记录和一个新的XID,由于我每个周期会更新80-90%的对象,因此我预计会有许多“旧”记录需要清理。 - MindJuice
值得注意的是,在运行第一步时,客户端可能还会针对第“0”步骤中数据库的“旧”状态发出读取请求,因此在生成新记录时需要保证旧记录仍然可用。 - MindJuice
3
你说的关于UPDATE操作会留下死元组的问题是正确的。但是Postgres可以通过HOT(“仅堆”)更新的方式重新利用该空间,而无需进行vacuum操作。但是有一些例外情况-特别是如果在更新中更改了索引列。另外,出于好奇,你还想到了哪些其他的MVCC数据库? - Erwin Brandstetter
我快速查看了HyperSQL(HSQLDB),CouchDB和H2。还有其他值得考虑的吗? - MindJuice
2
由于每次遍历都要进行大量更新,因此创建具有稀疏填充因子的表可能是值得的,以便在每个堆页面中为HOT更新留出足够的空间。 - dbenhur
1个回答

5
我认为Postgres在这种情况下应该能够胜任。这种情况并不常见,因此在大型更新之间进行手动清理似乎是一个合理的选择。
考虑一下,如果您可以这样做,即不进行大规模更新,而是生成一个新的表集,对其进行分析(必要时!),然后利用事务性DDL删除旧表并将新表重命名为它们的位置。这应该可以减轻您对VACUUM的担忧。
在这种情况下,您应该进行一些严格的调优。特别是,查看shared_buffers、与checkpoint相关的参数和与vacuum相关的参数。另外,请记住使用真实工作负载进行基准测试。

有趣的建议是使用两个单独的表格,最后再重命名。这对我可能很有效。我会好好考虑一下。谢谢! - MindJuice
要重命名一个表,数据库首先必须锁定该表。这比普通的行锁定更新要慢得多。 - Frank Heikens
1
@FrankHeikens:这是一个权衡,OP想要更新几乎整个表,短暂的排他锁可能比处理VACUUM等更好。如果读者只发出短查询,则尤其如此。或者,可以在客户端中执行此操作 - 小型search_path操作可能意味着“旧”读者使用旧模式中的表,新读者使用新模式中的表,而在后台您正在准备另一个版本。然后,您删除不再使用的模式。 - maniek
3
如果您选择在每个周期中使用“插入到新表”方式,请确保有一个单一的事务将正在使用的表重命名为“旧”名称,并将新表重命名为正在使用的表。在提交此事务并删除旧表之间留出一些时间,因为在提交后仍可能存在使用旧表OID计划的事务的小时间窗口。您可能需要在“移动新事务到位”的事务中以“DROP TABLE IF EXISTS”语句开始“旧”表名。 - kgrittn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接