sql - 有效地更新非常大的 PostgreSQL 数据库表

标签 sql database postgresql sql-update mvcc

我在 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/

相关文章:

mysql - 如何使用 SQL 查询连接数据库中具有相似名称的一组表?

android - Sqlite 命令用单个号码检索多条消息

mysql - 如何在sql中挑出某些名称

mysql - 需要帮助优化具有 100K+ 行的表的基本连接操作

php - MySQL查询选出成绩不全的学生 'A'

sql - 如何使用 JOIN 将列从一个表复制到另一个表

regex - postgresql:如何连接两个 regexp_matches()

sql - "@"符号在 SQL 中起什么作用?

php - html编码输出&&不正确的字符串错误

ruby-on-rails - 捆绑安装时出现 Postgresql 错误