Postgresql SERIAL 的工作方式是不是不同?
Posted
技术标签:
【中文标题】Postgresql SERIAL 的工作方式是不是不同?【英文标题】:Does Postgresql SERIAL work differently?Postgresql SERIAL 的工作方式是否不同? 【发布时间】:2013-08-25 17:17:27 【问题描述】:我有一个带有 SERIAL id 的 postgres 表。
id (serial) name age
插入通常发生在 Web 应用程序中。
我手动插入了两条新记录,将 id 设置为 max (id)+1****
在这 2 条插入之后,当网络应用插入 2 条记录时,它会给出重复键错误。
仅 2 条记录。之后一切正常。
问题是 - 为什么我的手动插入没有增加序列号?
自增和序列有区别吗?
我在这里缺少什么? mysql 或任何其他 SQL 是否有同样的问题?
【问题讨论】:
序列号是 PostgreSQL,这是一个自动递增的四字节整数,如果 id 是序列号,则不应生成自己的数字。在 MySQL 中,这或多或少是一个 AUTO_INCREMENT 列.. 【参考方案1】:当你创建一个serial
or bigserial
列时,PostgreSQL 实际上做了三件事:
-
创建
int
或bigint
列。
创建一个序列(由列拥有)以生成列的值。
将列的默认值设置为序列的nextval()
。
当您在未指定 serial
列的情况下插入值时(或者如果您明确指定 DEFAULT
作为其值),将在序列上调用 nextval
以:
-
返回列的下一个可用值。
增加序列的值。
如果您手动为 serial
列提供非默认值,则序列不会更新,nextval
可以返回您的 serial
列已经使用的值。因此,如果您执行此类操作,则必须通过调用 nextval
or setval
手动修复序列。
另外请记住,可以删除记录,因此serial
列中的空白是可以预料的,因此即使没有并发问题,使用max(id) + 1
也不是一个好主意。
如果您使用 serial
或 bigserial
,最好的办法是让 PostgreSQL 为您分配值,并假装它们是碰巧按特定顺序出现的不透明数字:不要自己分配它们,也不要假设它们只有唯一性。此经验法则适用于所有数据库 IMO。
我不确定 MySQL 的 auto_increment
如何适用于所有不同的数据库类型,但也许 the fine manual 会有所帮助。
【讨论】:
谢谢。我认为mysql中没有额外的序列。它只是自动增量ID。所以 max(id)+1 可以在 mysql 中工作,但不能在 postgres 中工作! 但它应该有触发串行序列增量?你的建议是什么?我知道它不是那样的。只是提个建议 我的建议在我的回答中:将serial
和 auto_increment
值留给数据库。根本不要惹他们。如果您让数据库分配serial
值,那么序列将被更新,一切都会好起来的;如果您手动分配一个值,那么您必须手动更新序列。
@zod 手动插入 postgres 数据库不会触发对序列的任何更改。他们为什么要这样做?【参考方案2】:
如果您想将一条记录插入到带有serial
列的表中 - 只需从查询中省略它 - 它将自动生成。
或者您可以使用以下内容插入其默认值:
insert into your_table(id, val)
values (default, '123');
第三种选择是直接从串行序列中取值:
insert into your_table(id, val)
values (nextval(pg_get_serial_sequence('your_table','id')), '123');
【讨论】:
谢谢...所以它与mysql不同..是吗? oracle和sql server中的顺序是一样的吗? @zod 在 Oracle 中也是一样,但我没有使用 MS SQL Server 的经验。 在未指定列时为 SERIAL 类型插入默认值的好答案。我一直在为 MySQL 中的 AUTO_INCREMENT 寻找 Postgres 的“null”插入等效项。谢谢。【参考方案3】:我手动插入了两条新记录,将 id 设置为 max (id)+1**
这种方法是完全错误的,在任何数据库中都不起作用。到目前为止,它仅在 MySQL 中对您有效。
如果两个连接同时运行此操作,它们将获得相同的 ID。只有锁定表以防止并发读取,它才能可靠地工作,这样一次只能有一个连接获取 ID。
这也是非常低效的。
这就是序列存在的原因,这样您就可以在存在并发插入器的情况下可靠地获取 ID。
只需使用:
INSERT INTO my_table(data1, data2) VALUES ('a','b') RETURNING id;
或:
INSERT INTO my_table(id, data1, data2) VALUES (DEFAULT, 'a','b') RETURNING id;
DEFAULT
是一个特殊的占位符,它告诉数据库从表定义中获取该列的默认值。默认为nextval('my_table_id_seq')
,因此将插入下一个序列值。
由于您询问的是关于序列的基本问题,我建议您还考虑序列不是无间隙的。序列有“洞”是正常的,其中表格值是 1、3、4、5、9、10,...。
【讨论】:
以上是关于Postgresql SERIAL 的工作方式是不是不同?的主要内容,如果未能解决你的问题,请参考以下文章
为啥这个查询这么慢? - PostgreSQL - 从 SERIAL、TIMESTAMP 和 NUMERIC(6,2) 中选择
如何使用 PostgreSQL 在 DBeaver 中创建自动递增/SERIAL id 列?
Postgresql ADD SERIAL COLUMN IF NOT EXISTS 仍在创建序列