有序序列生成

Cyb*_*rax 10 postgresql sequence

有没有办法为表记录生成某种有序标识符?

假设我们有两个线程在进行查询:

线程1:

begin;
insert into table1(id, value) values (nextval('table1_seq'), 'hello');
commit;
Run Code Online (Sandbox Code Playgroud)

线程2:

begin;
insert into table1(id, value) values (nextval('table1_seq'), 'world');
commit;
Run Code Online (Sandbox Code Playgroud)

完全可能(取决于时间)外部观察者会看到(2,'世界')记录出现在(1,'你好')之前.

这很好,但是我想要一种方法来获取自上次外部观察者检查它以来出现的'table1'中的所有记录.

那么,有没有办法按照插入的顺序获取记录?也许OID可以提供帮助?

Cra*_*ger 6

您想要的是强制事务以与插入相同的顺序提交(使其插入可见)。就其他客户而言,插入在提交之前不会发生,因为它们可能会回滚并消失。

即使您没有将插入内容包装在显式begin/中,情况也是如此commit。事务提交,即使是隐式完成的,仍然不一定按照行本身插入的顺序运行。它受操作系统 CPU 调度程序排序决策等的影响。

即使 PostgreSQL 支持脏读,这仍然是正确的。仅仅因为您按给定顺序开始三个插入并不意味着它们会按该顺序完成

没有简单或可靠的方法可以做您想要的事情来保留并发性。您需要在单个工作线程上按顺序执行插入操作,或者按照 Tometzky 的建议使用表锁定,这基本上具有相同的效果,因为在任何给定时间只有一个插入线程可以执行任何操作。

您可以使用建议锁定,但效果是相同的。

使用时间戳不会有帮助,因为您不知道对于任何两个时间戳,是否有一行时间戳位于两个时间戳之间尚未提交。

您不能依赖仅读取第一个“间隙”的行的标识列,因为由于回滚,在系统生成的列中间隙是正常的。

我认为您应该退后一步,看看为什么有这个要求,并且考虑到这个要求,为什么要使用单独的并发插入。

也许您从单个会话中进行小块批量插入会更好?


Erw*_*ter 5

不。由于数据库表中的行没有自然顺序,因此您需要处理的只是表中的值。

好吧,有Postgres 特定的系统列cminctid可以在某种程度上滥用。

元组 ID ( ctid) 包含文件块号和行在块中的位置。所以这代表了磁盘上的当前物理顺序。以后的添加会有更大的ctid通常。您的 SELECT 语句可能如下所示

SELECT *, ctid   -- save ctid from last row in last_ctid
FROM   tbl
WHERE  ctid > last_ctid
ORDER  BY ctid
Run Code Online (Sandbox Code Playgroud)

ctid有数据类型tid。例子:'(0,9)'::tid

然而,它作为长期标识符并不稳定,因为VACUUM任何并发UPDATE或其他一些操作都可以随时更改元组的物理位置。不过,在交易期间,它是稳定的。如果您只是插入而没有其他内容,它应该可以在本地为您的目的工作。

now()除了serial列之外,我还会添加一个默认的时间戳列......

我也会让列默认填充您的id列(aserialIDENTITY列)。这会在稍后阶段从序列中检索数字,而不是显式获取然后插入它,从而最小化(但不是消除)竞争条件的窗口 -id稍后插入较低值的机会。详细说明:

  • @MajidAzimi:默认行为是将插入的行附加到表的物理末尾。但这只是一个实施细节,并不能保证。一旦有并发事务,即使在那时,行也可能看起来是无序的。 (2认同)