PostgreSQL ---【序列】用法详解

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

🛠️ 序列的基本操作

1. 创建自定义序列

可以使用 CREATE SEQUENCE 语句来创建一个完全可控的序列:

sql 复制代码
    -- 基本语法 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. 将序列与表关联

在创建表时,或者为已存在的表添加自增属性时,可以将序列绑定到字段上:

sql 复制代码
    -- 创建表时关联序列 
    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. 删除序列

sql 复制代码
DROP SEQUENCE IF EXISTS test_seq; 
-- 如果序列被表引用,可以使用 CASCADE 强制删除并解除依赖 
DROP SEQUENCE IF EXISTS test_seq CASCADE;

4. 修改序列

🛠️ 使用 ALTER SEQUENCE 修改序列属性

ALTER SEQUENCE 命令可以灵活地修改序列的各项参数,包括重置起始值、调整步长、修改最大/最小值等6。

  • 重置序列的下一个值(最常用)
    使用 RESTART WITH 可以改变序列下一次调用 nextval() 时返回的值2。
sql 复制代码
    -- 将序列的下一个值重置为 1 
    
    ALTER SEQUENCE 序列名 RESTART WITH 1;
  • 修改步长、最大值、最小值等属性
    可以一次性修改序列的多个属性:
sql 复制代码
    ALTER SEQUENCE 序列名
    INCREMENT BY 2 -- 修改步长为 2
    MAXVALUE 1000000 -- 修改最大值为 100万 
    MINVALUE 0 -- 修改最小值为 0 
    CACHE 10 -- 修改缓存数量为 10 
    CYCLE; -- 开启达到最大值后循环
    
  • 修改序列的归属或拥有者

可以将序列绑定到某个表的特定字段(删除该字段时序列会自动删除),或者修改序列的所有者

sql 复制代码
    -- 将序列绑定到指定表的指定字段 
    ALTER SEQUENCE 序列名 OWNED BY 表名.字段名; 
    -- 解除序列与任何字段的绑定 
    ALTER SEQUENCE 序列名 OWNED BY NONE; 
    -- 修改序列的拥有者 ALTER SEQUENCE 序列名 OWNER TO 新用户名;
    
  • 修改序列的名称或模式
sql 复制代码
    -- 修改序列名 
    ALTER SEQUENCE 序列名 RENAME TO 新序列名; 
    -- 将序列移动到另一个 Schema 下 
    ALTER SEQUENCE 序列名 SET SCHEMA 新Schema名;
  • 使用 setval() 函数动态调整当前值

如果你需要根据表中现有的数据来动态调整序列(例如防止主键冲突),使用 setval() 函数会更加方便。

设置为固定值

sql 复制代码
    -- 将序列的当前值直接设置为 1000,下一次 nextval 将返回 1001 
    SELECT setval('序列名', 1000);

基于表中最大 ID 动态同步(强烈推荐)

当手动插入过数据导致序列与表数据不匹配时,可以使用此方法完美解决:

sql 复制代码
    -- 将序列的当前值同步为表中的最大 ID,避免下次插入时主键冲突 
    SELECT setval('序列名', (SELECT COALESCE(MAX(id), 0) FROM 表名));

💡 温馨提示

  • 权限要求 :执行 ALTER SEQUENCEsetval() 操作,你必须是该序列的所有者。
  • 事务特性ALTER SEQUENCE 的大部分操作(如 RESTART)是不可回滚的;而 setval() 在事务中是可以被回滚的。
  • 并发影响ALTER SEQUENCE 在修改期间会阻塞 nextvalsetval 等函数的调用,建议在业务低峰期执行。

⚙️ 序列的核心操作函数

PostgreSQL 提供了一系列函数来操作和获取序列值:

函数 作用 示例
nextval(序列名) 生成并返回下一个序列值(自动递增) SELECT nextval('test_seq');
currval(序列名) 获取当前会话中最后一次生成的序列值 SELECT currval('test_seq');
lastval() 获取当前会话中最后一次生成的任意序列值 SELECT lastval();
setval(序列名, 值) 直接设置序列的当前值 SELECT setval('test_seq', 200);
  • nextval() :最常用且最安全,即使在未提交的事务中调用也会消耗一个号(事务回滚后不退还)。
  • currval() :前提是当前会话必须先调用过 nextval(),否则会报错。常用于插入主表后,立即用该 ID 插入关联的子表。
  • lastval()慎用! 如果中间调用了其他序列,lastval() 返回的会是其他序列的值,在触发器或复杂函数中极易出错。

🚀 实战中的三种自增主键实现方式

在实际开发中,有三种常见的方式来实现自增主键,推荐程度依次递增:

1. 手动创建并绑定序列(最灵活)

如上文所示,手动创建序列后,在表定义中通过 DEFAULT nextval('序列名') 来使用。这种方式适合需要多个表共享同一个序列的场景。

2. 使用 SERIAL / BIGSERIAL(快捷方式)

SERIAL 并不是真实的数据类型,而是 PostgreSQL 提供的语法糖(快捷方式)。它会自动为你创建一个序列,并将其绑定到字段上。

  • SERIAL 等价于 INTEGER + 自动序列
  • BIGSERIAL 等价于 BIGINT + 自动序列(推荐,防止数据量大时溢出)
sql 复制代码
    CREATE TABLE users ( 
        id BIGSERIAL PRIMARY KEY, -- 自动创建 users_id_seq 并关联 
        username VARCHAR(50) NOT NULL 
    ); 

3. 使用 IDENTITY 列(SQL标准,强烈推荐 ✅) 从 PostgreSQL 10 开始,引入了符合 SQL 标准的 GENERATED AS IDENTITY。它的语义更清晰,明确表示"此列由系统生成",且工具兼容性更好

sql 复制代码
    CREATE TABLE products ( 
        id BIGINT GENERATED ALWAYS AS IDENTITY ( 
            START WITH 1000 
            INCREMENT BY 1 
            CACHE 10 
         ) PRIMARY KEY, 
        name TEXT NOT NULL 
     );

⚠️ 避坑指南与性能优化

  1. ID 不连续与事务回滚
    序列值一旦被 nextval() 获取,即使所在的事务回滚,这个值也不会被回收。因此,序列生成的 ID 可能会出现跳号(不连续)的情况,业务逻辑中不要强依赖 ID 的连续性。
  2. 手动插入 ID 导致的主键冲突
    如果你手动向表中插入了指定的 ID(例如 INSERT INTO users (id, name) VALUES (999, '张三')),序列的当前值并不会自动更新。下次自动插入时可能会因为 ID 重复而报错。

解决方法:手动同步序列值为表中的最大 ID。

sql 复制代码
    SELECT setval('users_id_seq', 
                (SELECT COALESCE(MAX(id), 0) FROM users));
  1. 高并发下的性能优化(CACHE)
    在并发量高的场景下,频繁获取序列值会产生争用(Sequence Contention)。可以通过增大 CACHE 值来优化,序列会预分配一批值到内存中,减少磁盘 I/O。例如 CACHE 1000 适合高并发场景,但缺点是数据库异常崩溃时,内存中未使用的缓存序列号会丢失,导致 ID 出现更大的跳跃。
sql 复制代码
    -- 高并发场景推荐配置 
    CREATE SEQUENCE high_perf_seq 
    CACHE 1000 
    NO CYCLE;
相关推荐
l1t2 小时前
DeepSeek总结的PostgreSQL 的开源 TDE:pg_tde
数据库·postgresql·开源
回家路上绕了弯2 小时前
AgentScope Harness 深度实战:让Java智能体从“Demo可用”走向“生产可用”
后端
卷心菜投手ovo2 小时前
RAG 为什么引用总是对不上?
后端·github
foggyprojects2 小时前
动态 SQL 模板里,权限条件为什么要注入而不是散落在业务代码里
后端
无风听海2 小时前
ASP.NET Core .NET 10 错误响应体系全景:从 BadRequest 到编译器基础设施
后端·asp.net·.net
文心快码BaiduComate2 小时前
从个人效能到组织资产:文心快码企业版Agent Hub上线,提升团队AI编程效能
前端·后端·程序员
雪隐3 小时前
个人电脑玩AI00-前言
人工智能·后端
数据库小学妹3 小时前
InnoDB内存架构解密:Buffer Pool与性能优化实战
数据库·经验分享·sql·性能优化·架构
Lyyaoo.3 小时前
【MySQL】SQL优化
android·sql·mysql