postgresql序列下一个val是否包含插入顺序?

时间:2017-07-03 01:39:28

标签: postgresql

给出一个包含id bigint default next_val('foo_sequence')

的表格

我可以假设id的顺序包含插入顺序吗?

我的意思是后面插入的id总是大于先前插入的ID。

我正在尝试计算并保存一个增量连续行数

我是这样做的

SELECT count(*) as seq_no from foo where id < some_id;
// get the seq no

UPDATE foo SET seq_no = seq_no_above + 1 WHERE id = some_id;

但它有时会给出重复的seq_no值, 如果id包含插入顺序,则它不应具有重复值。

1 个答案:

答案 0 :(得分:6)

在最简单和最纯粹的意义上,是的。这取决于你早先&#34;的意思。然而,&#34;稍后&#34;,因为您必须考虑打开交易并关闭交易。如果事务尚未提交,那么理论上记录稍后可能会显示较早的ID。

在插入发生时分配ID,但在提交记录之前记录不会显示。因此,如果提交顺序不同,您可能会看到一些奇怪的行为,具体取决于您的用例的严格程度。

Open Transaction A
Insert records 1,2

Open Transaction B
Insert records 3,4
Close transaction B

Select * (get 3,4)

Close transaction A

Select * (get 1,2,3,4)

您还必须担心缓存是否认为它们是顺序的。来自(非常好)Postgres docs

  

此外,尽管保证分配多个会话   不同的序列值,可能会生成值   考虑所有会话时的顺序。例如,用   缓存设置为10,会话A可能会保留值1..10并返回   nextval = 1,然后会话B可以保留值11..20并返回   在会话A生成nextval = 2之前,nextval = 11。因此,用   一个缓存设置可以安全地假设nextval值是   顺序生成;缓存设置大于1   应该只假设nextval值都是不同的,而不是   它们是纯粹顺序生成的。此外,last_value将反映出来   任何会话保留的最新值,无论是否还有   nextval返回。

最后一个警告是,具有适当权限的人总是可以将序列重置为不同的值,这显然会让事情变得棘手。

编辑:

要解决上面的用例,你肯定想要使用序列(并且可能还要添加NOT NULL / PRIMARY KEY约束,以确保唯一性)。至少在pgAdmin中,您可以通过设置数据类型serial来完成所有这些操作。虽然我已经提到过警告,但是出于99%的实际目的,你可以获得你想要的唯一性和顺序排序(因此序列)。

在任何情况下,我们都需要查看示例数据以确认您看到重复的原因(how to create a reproducible example)。我认为您看到的重复内容位于seq_no而不是id,这表明问题是您的查询。如果重复在id,那么您还有其他问题,这可以解释seq_no中的重复问题。

序列对于数据中的事务定义要好得多(它们为您提供唯一性,在并发性方面表现良好,并且不会导致重复......加上大部分时间都会获得顺序排序)。对于唯一键,它们最适用于NOT NULLPRIMARY KEYUNIQUE约束。

但如果你需要一个完美的增量,最好做一些类似下面的事情:

select *, row_number() over (order by value) as id
from foo
;

Postgres window functions非常强大,但绝对不是用于使用顺序键插入数据的标准。事后,它们对报告,分析和复杂查询更有用。