PostgreSQL 中的序列(Sequence)是一个独立的数据库对象,专门用于生成唯一的递增整数,最常用于为表字段生成自增主键。下面详细解析序列的用法、核心函数以及实战中的避坑指南。

1. 创建自定义序列
可以使用 CREATE SEQUENCE 语句来创建一个完全可控的序列:
-- 基本语法 CREATE SEQUENCE 序列名 [INCREMENT BY 步长] -- 默认为1,可设为负数(递减) [START WITH 起始值] -- 默认为1 [MINVALUE 最小值] -- 默认为1(递增时) [MAXVALUE 最大值] -- 默认为 2^31-1(int类型) [CACHE 缓存数量] -- 缓存序列值以提高性能,默认1 [CYCLE | NO CYCLE]; -- 达到最大值后是否循环,默认不循环 -- 示例:创建从100开始,步长为2,不设置最大值的序列 CREATE SEQUENCE test_seq START WITH 100 INCREMENT BY 2 NO MAXVALUE CACHE 1;
2. 将序列与表关联
在创建表时,或者为已存在的表添加自增属性时,可以将序列绑定到字段上:
-- 创建表时关联序列 CREATE TABLE test_table ( id INT PRIMARY KEY DEFAULT nextval('test_seq'), -- 插入时自动取序列值 content TEXT ); -- 为已存在的表关联序列 ALTER TABLE existing_table ALTER COLUMN id SET DEFAULT nextval('test_seq');3. 删除序列
DROP SEQUENCE IF EXISTS test_seq; -- 如果序列被表引用,可以使用 CASCADE 强制删除并解除依赖 DROP SEQUENCE IF EXISTS test_seq CASCADE;
4. 修改序列
?️ 使用 ALTER SEQUENCE 修改序列属性
ALTER SEQUENCE 命令可以灵活地修改序列的各项参数,包括重置起始值、调整步长、修改最大/最小值等6。
使用 RESTART WITH 可以改变序列下一次调用 nextval() 时返回的值2。
-- 将序列的下一个值重置为 1 ALTER SEQUENCE 序列名 RESTART WITH 1;
可以一次性修改序列的多个属性:
ALTER SEQUENCE 序列名 INCREMENT BY 2 -- 修改步长为 2 MAXVALUE 1000000 -- 修改最大值为 100万 MINVALUE 0 -- 修改最小值为 0 CACHE 10 -- 修改缓存数量为 10 CYCLE; -- 开启达到最大值后循环
可以将序列绑定到某个表的特定字段(删除该字段时序列会自动删除),或者修改序列的所有者
-- 将序列绑定到指定表的指定字段 ALTER SEQUENCE 序列名 OWNED BY 表名.字段名; -- 解除序列与任何字段的绑定 ALTER SEQUENCE 序列名 OWNED BY NONE; -- 修改序列的拥有者 ALTER SEQUENCE 序列名 OWNER TO 新用户名;
-- 修改序列名 ALTER SEQUENCE 序列名 RENAME TO 新序列名; -- 将序列移动到另一个 Schema 下 ALTER SEQUENCE 序列名 SET SCHEMA 新Schema名;
setval() 函数动态调整当前值如果需要根据表中现有的数据来动态调整序列(例如防止主键冲突),使用 setval() 函数会更加方便。
设置为固定值
-- 将序列的当前值直接设置为 1000,下一次 nextval 将返回 1001 SELECT setval('序列名', 1000);基于表中最大 ID 动态同步(强烈推荐)
当手动插入过数据导致序列与表数据不匹配时,可以使用此方法完美解决:
-- 将序列的当前值同步为表中的最大 ID,避免下次插入时主键冲突 SELECT setval('序列名', (SELECT COALESCE(MAX(id), 0) FROM 表名));PostgreSQL 提供了一系列函数来操作和获取序列值:
| 函数 | 作用 | 示例 |
|---|---|---|
| nextval(序列名) | 生成并返回下一个序列值(自动递增) | SELECT nextval('test_seq'); |
| currval(序列名) | 获取当前会话中最后一次生成的序列值 | SELECT currval('test_seq'); |
| lastval() | 获取当前会话中最后一次生成的任意序列值 | SELECT lastval(); |
| setval(序列名, 值) | 直接设置序列的当前值 | SELECT setval('test_seq', 200); |
在实际开发中,有三种常见的方式来实现自增主键,推荐程度依次递增:
1. 手动创建并绑定序列(最灵活)
如上文所示,手动创建序列后,在表定义中通过 DEFAULT nextval('序列名') 来使用。这种方式适合需要多个表共享同一个序列的场景。
2. 使用 SERIAL / BIGSERIAL(快捷方式)
SERIAL 并不是真实的数据类型,而是 PostgreSQL 提供的语法糖(快捷方式)。它会自动为创建一个序列,并将其绑定到字段上。
CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, -- 自动创建 users_id_seq 并关联 username VARCHAR(50) NOT NULL );
3. 使用 IDENTITY 列(SQL标准,强烈推荐 ✅) 从 PostgreSQL 10 开始,引入了符合 SQL 标准的 GENERATED AS IDENTITY。它的语义更清晰,明确表示“此列由系统生成”,且工具兼容性更好
CREATE TABLE products ( id BIGINT GENERATED ALWAYS AS IDENTITY ( START WITH 1000 INCREMENT BY 1 CACHE 10 ) PRIMARY KEY, name TEXT NOT NULL );
序列值一旦被 nextval() 获取,即使所在的事务回滚,这个值也不会被回收。因此,序列生成的 ID 可能会出现跳号(不连续)的情况,业务逻辑中不要强依赖 ID 的连续性。
如果手动向表中插入了指定的 ID(例如 INSERT INTO users (id, name) VALUES (999, '张三')),序列的当前值并不会自动更新。下次自动插入时可能会因为 ID 重复而报错。
解决方法:手动同步序列值为表中的最大 ID。
SELECT setval('users_id_seq', (SELECT COALESCE(MAX(id), 0) FROM users));在并发量高的场景下,频繁获取序列值会产生争用(Sequence Contention)。可以通过增大 CACHE 值来优化,序列会预分配一批值到内存中,减少磁盘 I/O。例如 CACHE 1000 适合高并发场景,但缺点是数据库异常崩溃时,内存中未使用的缓存序列号会丢失,导致 ID 出现更大的跳跃。
-- 高并发场景推荐配置 CREATE SEQUENCE high_perf_seq CACHE 1000 NO CYCLE;
ALTER SEQUENCE 对关联表的影响,主要取决于具体修改了序列的哪个属性。总体来说,它的影响可以分为“生命周期绑定”和“数据生成影响”两个层面:
这是 ALTER SEQUENCE 对关联表最直接的影响。通过 OWNED BY 子句,可以将序列与表的特定字段进行绑定或解绑:
当修改序列的步长、最大值、起始值等属性时,不会改变表的结构,也不会修改表中已经存在的数据。它的影响主要体现在未来插入的新数据上:
对现有数据无影响:修改序列的最大值或重置序列值,绝对不会更新或删除表中已经生成的 ID。
对后续插入的影响:
性能与并发影响:
总结建议:
如果只是修改序列的生成规则,只要确保新规则不会导致主键冲突或超出范围,对关联表就是安全的。如果涉及到 OWNED BY 的绑定操作,则需要考虑到未来删除表时的连带效应。
ALTER SEQUENCE 对正在运行的事务确实有影响,但这种影响并不是“一刀切”的,而是分为“立即生效”和“延迟生效”两种情况。具体取决于修改的是序列的哪部分属性:
当修改序列的生成参数(例如 RESTART WITH、INCREMENT BY、MAXVALUE、MINVALUE、CYCLE 等)时:
ALTER SEQUENCE 在执行期间会直接阻塞其他并发事务对 nextval、currval、lastval 和 setval 等函数的调用。这意味着如果的业务正处于高并发状态,执行这些修改可能会导致短暂的请求卡顿。如果为序列设置了缓存(CACHE 参数大于 1),其他正在运行的事务(后台会话)可能会受到影响:
当修改序列的元数据属性(例如 OWNED BY、OWNER TO、RENAME TO、SET SCHEMA)时:
ROLLBACK,这些改动会被撤销。nextval 等序列函数调用5。currval 状态(当前会话最后一次获取的值)。ALTER SEQUENCE 在执行期间会阻塞并发的序列值获取操作,强烈建议在业务低峰期或维护窗口执行该命令,以避免对线上正在运行的事务造成卡顿或性能抖动。