导读:本期聚焦于深圳程序员创作的《PostgreSQL序列SEQUENCE如何创建与重置?详解操作步骤与常见问题》,敬请观看详情。序列是PostgreSQL中用来生成自增数字的重要对象,常被用作表的主键默认值。本文围绕序列的创建与重置展开,先介绍CREATE SEQUENCE的基本语法和常用参数,包括起始值、步长、最大值以及循环选项的含义,再演示如何将序列绑定到表字段实现自增效果。针对序列与表字段不同步这一高频问题,详细说明使用setval函数重置序列当前值的具体方法,并补充如何通过pg_sequences视图查看序列状态、如何处理序列归属列的调整等实用技巧,帮助读者避开使用序列过程中的常见坑。

在使用PostgreSQL设计表结构时,自增主键几乎是绕不开的需求。虽然SERIAL和IDENTITY列可以简化操作,但它们的底层都依赖序列(SEQUENCE)对象。理解序列的创建方式、参数含义以及重置方法,对排查主键冲突、数据迁移后的序列修复等问题非常关键。本文将从零开始介绍PostgreSQL序列的完整用法。

PostgreSQL序列SEQUENCE如何创建与重置?详解操作步骤与常见问题

一、什么是序列以及如何创建

序列是PostgreSQL提供的一种数据库对象,本质上是一个特殊的单行表,专门负责产生有序的数字。它独立于普通表存在,可以被多个表共享,也可以单独调用。数据库保证每次从序列取值时都是原子操作,即使在大量并发请求下也不会产生重复值,这正是它适合做唯一标识的原因。

创建序列使用CREATE SEQUENCE语句,最简单的形式只需要一个名字:

-- 创建一个最简单的序列,默认从1开始,步长为1
CREATE SEQUENCE order_seq;

实际生产中往往会带上更多参数,下面是一个完整的例子:

CREATE SEQUENCE order_seq
    START WITH 1000      -- 起始值
    INCREMENT BY 1       -- 每次递增的步长
    MINVALUE 1000        -- 最小值
    MAXVALUE 999999999   -- 最大值
    CACHE 20             -- 预分配缓存,提升并发性能
    NO CYCLE;            -- 到达最大值后不再循环

几个参数值得展开说明。START WITH决定第一个取出的值是多少,适合从某个业务编号起步的场景。INCREMENT BY可以是负数,表示递减序列,但要注意递减序列的默认最小值和最大值方向也会反过来。CACHE选项指定数据库一次性预分配多少个值放在内存中,高并发写入时能明显减少磁盘更新次数,代价是数据库异常重启后缓存中未用完的值会被丢弃,产生空洞。CYCLE则允许序列到达边界后从头再来,做编号循环复用时有用,但用于主键时务必保持NO CYCLE,否则会撞出重复键。

序列创建好之后,取值主要靠三个函数:nextval取下一个值并推进序列,currval返回当前会话最近一次通过nextval取到的值,setval直接设置序列的当前值。需要注意currval在会话没有调用过nextval之前使用会报错,它返回的不是全局意义上的当前值。

二、序列与表字段的绑定

单独的序列用处有限,更多时候我们希望它作为表字段的默认值来实现自增。绑定方式是给字段设置DEFAULT表达式:

CREATE TABLE orders (
    id      bigint NOT NULL DEFAULT nextval('order_seq'),
    orderno text,
    PRIMARY KEY (id)
);

这样插入数据时不指定id,数据库会自动从序列取值:

INSERT INTO orders (orderno) VALUES ('A001');
SELECT currval('order_seq');  -- 查看本会话刚取到的值

更推荐的做法是使用OWNED BY把序列的归属绑定到具体字段,这样删除字段或表时序列会一起被删除,避免残留孤儿对象:

ALTER SEQUENCE order_seq OWNED BY orders.id;

值得一提的是,常见的SERIAL写法其实就是上面这套动作的语法糖。id serial会自动创建一个序列并绑定到id列。而从PostgreSQL 10开始,官方更推荐使用GENERATED AS IDENTITY写法,它符合SQL标准,并且能防止用户不经意间手动给自增列插入值导致的混乱。三种方式各有适用场景,老系统迁移维护时接触SERIAL和裸序列更多,新项目则建议优先考虑IDENTITY。

如果想知道某个表字段用的是哪个序列,可以通过pg_get_serial_sequence函数查询:

SELECT pg_get_serial_sequence('orders', 'id');
-- 返回结果类似 public.order_seq

三、序列重置的正确姿势

序列最经典的故障场景是这样的:通过COPY或INSERT指定id的方式导入了一批数据,id最大值到了5000,但序列还停在10。此时再依赖序列自增插入,就会报duplicate key value violates unique constraint错误。解决办法就是把序列重置到正确位置,核心工具是setval函数。

setval有两种调用形式。三参数形式setval('seq_name', value, is_called)中,当is_called为true时,下一次nextval返回value加步长;为false时,下一次nextval直接返回value。两参数形式等价于三参数且is_called为true。重置时通常配合查询表中的最大id:

-- 将序列重置为表中id的最大值,下一次自增值从10001开始
SELECT setval(pg_get_serial_sequence('orders', 'id'),
       (SELECT COALESCE(MAX(id), 0) FROM orders));

这里用COALESCE处理空表情况很实用:表里没数据时MAX返回NULL,直接传给setval会报错,兜底为0后序列下一次从1开始,符合预期。如果想让序列从头计数,也可以用ALTER SEQUENCE ... RESTART WITH

ALTER SEQUENCE order_seq RESTART WITH 1;

重置之外,日常运维还需要掌握查看序列状态的方法。查询pg_sequences视图可以看到每个序列的当前值、步长和缓存:

SELECT sequencename, last_value, increment_by, cache_size
FROM pg_sequences
WHERE schemaname = 'public';

另外有两个容易踩的坑。第一,序列不是事务性的精确恢复对象,事务回滚时序列取出的值不会退回,这是为了保证并发性能,属于正常现象,不要误以为是bug。第二,序列值只能保证不重复,不保证连续,开启CACHE或发生回滚后都会出现跳号。如果业务要求订单号严格连续,序列方案并不合适,应该考虑单独的号码表加行锁,或者用应用层发号服务。理解这些边界,才能在设计阶段就选对工具。

PostgreSQL序列SEQUENCE创建序列重置修改时间:2026-09-12 17:58:31

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260912/55461.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。