我想使用 PostgreSQL 表作为文档的一种工作队列。每个文档都有一个 ID,并存储在另一个带有许多附加列的普通表中。但是这个问题是关于为工作队列创建表的。
我想为这个队列创建一个没有 OID 的表,只有一列:文档的 ID 为整数。如果此工作队列表中存在文档的 ID,则表示具有该 ID 的文档是脏的,必须进行一些处理。额外的表应避免 VACUUM 和死元组问题以及事务死锁,如果主文档表中的每个文档条目上只有一个脏位,则会出现这些事务。
我系统的许多部分会将文档标记为脏,因此会将要处理的 ID 插入到该表中。这些插入将用于一个事务中的多个 ID。我不想使用任何类型的嵌套事务,并且似乎没有任何类型的 INSERT IF NOT EXISTS 命令。我宁愿在表中有重复的 ID。因此,该表中唯一的列必须可以重复。
处理工作队列的进程将删除所有进程 ID,因此会处理重复项。(顺便说一句:下一步还有另一个队列,所以关于竞争条件,这个想法应该是干净的并且没有问题)
但我也希望按顺序处理文件:总是先处理 ID 较小的文件。
因此,我希望在 ID 列(工作队列表中的唯一列)上有一个帮助 LIMIT 和 ORDER BY 的索引。理想情况下,我只有一列,这应该是主键。但是主键不能有重复项,所以我似乎不能这样做。
如果没有索引,ORDER BY 和 LIMIT 会很慢。
我可以在该列上添加一个普通的二级索引。但我担心 PostgreSQL 会在磁盘上添加第二个文件(PostgreSQL 会为每个额外的索引执行此操作)并对该表使用双倍数量的磁盘操作。
最好的事情是什么?添加一个带有随机内容(如 OID)的虚拟列,以使主键不会抱怨重复?我必须在我的队列表中浪费那个空间吗?
或者添加第二个索引是无害的,它会成为直接在主元组 btree 中的主索引吗?
我应该删除上面的所有内容并留下以下内容吗?最初的问题让人分心,并且包含太多不相关的信息。
我想在 PostgreSQL 中有一个具有以下属性的表:
- 一列有一个整数
- 允许重复
- 列上高效的 ORDER BY+LIMIT
- INSERT 不应在该表或任何类型的唯一索引中执行任何查询。INSERT 应该只为该表的主文件/主 btree 找到最佳页面,并将行插入到其他行之间,按 ID 排序。
- INSERT 将批量发生,并且不能失败,预计磁盘已满等。
- 此表不应有额外的 btree 文件,因此没有二级索引
- 行不应占用太多空间,例如没有 OID
我想不出解决所有这些问题的解决方案。
我唯一的解决方案是在最后一个要点上妥协:添加一个覆盖整数的主键和一个虚拟列,如 OID、时间戳或序列。
另一种解决方案要么使用假设的 INSERT IF NOT EXISTS,要么使用嵌套事务或带有 WHERE 的特殊 INSERT。所有这些解决方案都会在插入时添加对 btree 的查询。它们也可能导致死锁。
(也在这里发布:https ://dba.stackexchange.com/q/45126/7788 )