我在 PostgresQL 中有一个非常大的数据库表和一个像“已复制”的列。每个新行开始时都未复制,稍后将由后台程序复制到另一件事。该表“btree(ID) WHERE replicated=0”上有一个部分索引。后台程序最多选择 2000 个条目(LIMIT 2000),对其进行处理,然后使用 2000 个准备好的 sql 命令在一个事务中提交更改。
现在的问题是我想给用户一个选项来重置这个复制值,让它再次全部为零。
一个更新表set replicated=0;
不可能:
- 这需要很多时间
- 由于 MVCC,它复制了 tabel 的大小
- 它是在一次交易中完成的:要么失败要么通过。
对于这种情况,我实际上不需要事务功能:如果系统出现故障,它应该只处理其中的一部分。
其他几个问题: 做一个
update set replicated=0 where id >10000 and id<20000
也很糟糕:它对整个表进行顺序扫描,这太慢了。 如果它不这样做,它仍然会很慢,因为它会查找太多。
我真正需要的是一种遍历所有行、更改它们而不是绑定(bind)到巨大事务的方法。
奇怪的是,一个
UPDATE table
SET replicated=0
WHERE ID in (SELECT id from table WHERE replicated= LIMIT 10000)
也很慢,尽管这应该是一件好事:按磁盘顺序遍历表格...
(请注意,在那种情况下,还有一个索引涵盖了这一点)
(像 Mysql 这样的更新 LIMIT 对 PostgresQL 不可用)
顺便说一句:真正的问题要复杂得多,我们在这里讨论的是一个已经部署的嵌入式系统,所以远程模式更改很困难,但有可能 不幸的是,它是 PostgresQL 7.4。
我说的行数是例如90000000,数据库大小可达几十G。
数据库本身只有5张表,一张很大。 但这并不是糟糕的设计,因为这些嵌入式盒子只使用一种实体进行操作,它不是 ERP 系统或类似的东西!
有什么想法吗?
最佳答案
如何添加一个新表来存储这个复制值(以及一个主键来将每条记录链接到主表)。然后您只需为每个复制的项目添加一条记录,并删除记录以删除复制标志。 (或者可能反过来 - 每个非复制记录的记录,取决于常见情况)。
当你想将它们全部设置回 0 时,这也会简化这种情况,因为你可以截断表(这会将磁盘上的表大小归零,你甚至不必清理空间来释放空间)
关于sql - 有效地更新非常大的 PostgreSQL 数据库表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/112249/