PostgreSQL序列不按1递增

huangapple go评论99阅读模式
英文:

Postgresql Sequence not increase by 1

问题

我在PostgreSQL表中使用一个8位数字的起始序列,如下:

20000101
20000102

并且在API(AWS Lambda)中使用SQLAlchemy ORM执行INSERT查询,如下:

result = session.query("select nextval('mydb.student_id_seq')").one_or_none()
id = result[0]

student_model = Student(
    id=id,
    name="Name",
    class_id="Class ID",
    grade="A"
)

但有时序列号会增加一个随机数,或者回滚到先前的数字,如下:

20000200
20000201
20000202
20000214
20000215
20000221
20000222

如何解决这个问题?

我想知道如何在SQLAlchemy中正确使用PostgreSQL序列。

英文:

I use a sequence in the PostgreSQL table with an 8-digits start number like:

20000101
20000102

And execute INSERT query with SQLAlchemy ORM in API (AWS lambda) like:

result = session.query("select nextval('mydb.student_id_seq')").one_or_none()
id = result[0]

student_model = Student(
    id=id,
    name="Name",
    class_id="Class ID",
    grade="A"
)

But sometimes a sequence number increases by a random number or roll-back to the previous number like:

20000200
20000201
20000202
20000214
20000215
20000221
20000222

How can I solve this problem?

I want to know How to use the PostgreSQL Sequence in SQLAlchemy correctly.

答案1

得分: 2

因为序列缓存。您使用的客户端可以请求并保留序列的下一个N个数字,然后丢弃没有使用的那些。其他人可以稍后获取这些返回,或者必须使用已被其他人保留的数字以上的数字。

不要依赖于从您不拥有/专用并且无法锁定的非临时序列的nextval()的连续性。从上面链接的文档中:

>由于nextvalsetval调用永远不会回滚,如果需要“无缝”分配序列号,则不能使用序列对象。可以通过对包含计数器的表进行排他锁定来构建无缝的分配;但是,这个解决方案比序列对象要显然昂贵,特别是如果许多事务需要同时使用序列号。

>如果为将由多个会话同时使用的序列对象使用大于一的*cache设置,可能会获得意外的结果。每个会话将在对序列对象的一次访问中分配和缓存连续的序列值,并相应地增加序列对象的last_value。然后,在该会话中对nextval的下一cache*-1次使用只需返回预分配的值,而无需触及序列对象。因此,在会话结束时未使用的分配但未使用的任何数字将丢失,导致序列中的“空隙”。

>此外,虽然可以保证多个会话分配不同的序列值,但在考虑所有会话时生成的值可能是无序的。

在模型中,您不需要手动处理id序列并加以保护。使该字段使用作为生成标识的整数。

英文:

It's because of sequence caching. The client you use can request and reserve next N numbers from the sequence, then discard the ones it didn't use. Someone else can get those returns later, or have to use numbers above what's already reserved by others.

Don't rely on the continuity of nextval() from a non-temp sequence you don't own/use exclusively and can't lock. From the doc linked above:

>Because nextval and setval calls are never rolled back, sequence objects cannot be used if “gapless” assignment of sequence numbers is needed. It is possible to build gapless assignment by using exclusive locking of a table containing a counter; but this solution is much more expensive than sequence objects, especially if many transactions need sequence numbers concurrently.
>
>Unexpected results might be obtained if a cache setting greater than one is used for a sequence object that will be used concurrently by multiple sessions. Each session will allocate and cache successive sequence values during one access to the sequence object and increase the sequence object's last_value accordingly. Then, the next cache-1 uses of nextval within that session simply return the preallocated values without touching the sequence object. So, any numbers allocated but not used within a session will be lost when that session ends, resulting in “holes” in the sequence.
>
>Furthermore, although multiple sessions are guaranteed to allocate distinct sequence values, the values might be generated out of sequence when all the sessions are considered.

You don't need to manually handle the id sequence in your model and guard it. Make the field use an integer generated as identity.

huangapple
  • 本文由 发表于 2023年3月15日 21:09:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/75745181.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定