本文主要介绍 PostgreSQL的自动增长机制,包括 SERIAL(传统方式)、IDENTITY(推荐标准)和 SEQUENCE(底层对象)三种实现,具有一定的参考价值,感兴趣的可以了解一下
下面是一份 PostgreSQL 自动增长(AUTO INCREMENT) 的 完整实战手册,涵盖 序列(SEQUENCE)、SERIAL、IDENTITY、自定义、并发安全、性能、迁移、常见陷阱与最佳实践,适合开发、DBA、架构师使用。
一、PostgreSQL 的自动增长机制
PostgreSQL 不使用 AUTO_INCREMENT 关键字(那是 MySQL 的写法),而是使用 序列(SEQUENCE) + SERIAL / IDENTITY。
| 方式 | 说明 |
|---|
| SERIAL | 老版本兼容(内部创建序列) |
| IDENTITY | SQL 标准,推荐(PostgreSQL 10+) |
| SEQUENCE | 底层对象,可独立管理 |
二、三种实现方式对比
| 方式 | 语法 | 是否标准 | 是否可控 | 推荐 |
|---|
| SERIAL | id SERIAL | 否 | 一般 | 兼容旧项目 |
| BIGSERIAL | id BIGSERIAL | 否 | 一般 | 大数据量 |
| IDENTITY | id GENERATED ALWAYS AS IDENTITY | 是 | 高 | 强烈推荐 |
三、基本使用示例
1.SERIAL(传统方式)
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT
);
-- 插入时自动增长
INSERT INTO users(name) VALUES ('Alice');
-- id = 1
INSERT INTO users(name) VALUES ('Bob');
-- id = 2
内部自动创建:users_id_seq
2.IDENTITY(推荐方式)
CREATE TABLE products (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT,
price NUMERIC
);
-- 插入
INSERT INTO products(name, price) VALUES ('iPhone', 999);
-- id = 1
两种 IDENTITY 模式
| 模式 | 说明 |
|---|
| GENERATED ALWAYS | 默认,禁止手动插入 |
| GENERATED BY DEFAULT | 允许手动插入(若不填则自动) |
-- 允许手动指定 ID
CREATE TABLE logs (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
message TEXT
);
INSERT INTO logs(id, message) VALUES (100, 'Custom ID');
四、序列(SEQUENCE)底层原理
-- 查看自动创建的序列
SELECT pg_get_serial_sequence('users', 'id');
-- 返回: public.users_id_seq
-- 直接操作序列
SELECT nextval('users_id_seq'); -- 获取下一个值
SELECT setval('users_id_seq', 100); -- 设置当前值
SELECT currval('users_id_seq'); -- 获取当前值(事务内)
手动创建序列
CREATE SEQUENCE my_seq
START WITH 1000
INCREMENT BY 1
MINVALUE 1
MAXVALUE 999999
CACHE 10;
CREATE TABLE orders (
id INT PRIMARY KEY DEFAULT nextval('my_seq'),
total NUMERIC
);
五、IDENTITY vs SERIAL 详细对比
| 特性 | SERIAL | IDENTITY |
|---|
| SQL 标准 | 否 | 是 |
| 可显式插入 | 允许 | ALWAYS 禁止,BY DEFAULT 允许 |
| 序列名固定 | 是(table_col_seq) | 是(系统命名) |
| 可重用序列 | 困难 | 容易 |
| 迁移兼容性 | 好 | 需 PostgreSQL 10+ |
| 推荐度 | 3 stars | 5 stars |
六、常见操作:重置、跳跃、修复
1. 重置 ID 从 1 开始
-- SERIAL 表
TRUNCATE TABLE users RESTART IDENTITY;
-- 或手动
SELECT setval(pg_get_serial_sequence('users', 'id'), 1, false);
2. 修复 ID 空洞(不推荐频繁操作)
-- 重新编号(慎用!影响外键)
WITH ranked AS (
SELECT id, row_number() OVER (ORDER BY id) AS rn
FROM users
)
UPDATE users u
SET id = r.rn
FROM ranked r
WHERE u.id = r.id;
3. 跳过一段 ID(预留)
SELECT setval('users_id_seq', 10000);
-- 下一个 INSERT 从 10001 开始
七、并发安全与性能
| 场景 | 行为 |
|---|
| 高并发插入 | 安全(序列是事务安全的) |
| 事务回滚 | ID 不回退(序列已分配) |
| 缓存(CACHE) | 提升性能,但回滚会造成空洞 |
-- 创建高性能序列
CREATE SEQUENCE fast_seq CACHE 100;
-- 100 个值预分配,减少锁竞争
空洞是正常现象,不要试图消除
八、与外键、复制、迁移
1. 外键引用
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
user_id INT REFERENCES users(id)
);
-- 没问题
2. 逻辑复制 / pg_dump
IDENTITY 列会自动处理SERIAL 需注意序列权限
-- 导出时包含序列
pg_dump -Fc -f backup.dump dbname
3. MySQL 迁移到 PostgreSQL
-- MySQL
id INT AUTO_INCREMENT PRIMARY KEY
-- 转为 PostgreSQL
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
九、查看与管理序列
-- 查看所有序列
SELECT * FROM information_schema.sequences;
-- 查看系统序列
SELECT schemaname, sequencename, last_value
FROM pg_sequences;
-- 修改序列
ALTER SEQUENCE users_id_seq
INCREMENT BY 2
MINVALUE 1
MAXVALUE 1000000
RESTART WITH 1;
十、常见错误与避坑
| 错误 | 原因 | 解决 |
|---|
| ERROR: duplicate key value violates unique constraint | 手动插入冲突 | 用 BY DEFAULT 或 OVERRIDING SYSTEM VALUE |
| sequence is not yet defined in this session | currval() 未调用 nextval() | 先 nextval() |
| ID 跳跃 | 事务回滚、CACHE | 正常现象 |
| 迁移后 ID 从 1 开始 | 未 RESTART IDENTITY | TRUNCATE ... RESTART IDENTITY |
| GENERATED ALWAYS 插入失败 | 显式插入 | 省略列或用 BY DEFAULT |
插入时覆盖 IDENTITY(特殊场景)
INSERT INTO products(id, name)
VALUES (999, 'Legacy Product')
OVERRIDING SYSTEM VALUE;
十一、最佳实践脚本
1. 标准建表模板(推荐)
CREATE TABLE customers (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 触发器自动更新 updated_at
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_customers_updated_at
BEFORE UPDATE ON customers
FOR EACH ROW
EXECUTE FUNCTION update_timestamp();
2. 安全插入(支持覆盖)
-- 允许导入旧数据
INSERT INTO customers(id, email, name)
VALUES (1001, 'old@example.com', 'Legacy User')
OVERRIDING SYSTEM VALUE;
3. 重置测试数据
TRUNCATE TABLE customers, orders, products RESTART IDENTITY CASCADE;
十二、性能优化建议
| 建议 | 说明 |
|---|
| 用 BIGINT 而非 INT | 避免溢出 |
| 序列 CACHE 20~100 | 提升插入性能 |
| 分区表用独立序列 | 避免热点 |
| 避免 SELECT currval() | 用 RETURNING id |
-- 插入并返回 ID(推荐)
INSERT INTO users(name) VALUES ('Tom')
RETURNING id;
十三、速查表
| 命令 | 用途 |
|---|
| SERIAL | 自动创建序列 |
| GENERATED ALWAYS AS IDENTITY | 标准,禁止手动插入 |
| GENERATED BY DEFAULT AS IDENTITY | 允许手动插入 |
| nextval('seq') | 获取下一个值 |
| setval('seq', n) | 设置当前值 |
| TRUNCATE ... RESTART IDENTITY | 重置序列 |
| OVERRIDING SYSTEM VALUE | 插入时覆盖 ID |
| RETURNING id | 获取插入的 ID |
十四、决策树

十五、常见面试题
| 问题 | 答案 |
|---|
| PostgreSQL 如何实现自增? | 使用 SEQUENCE |
| SERIAL 和 IDENTITY 区别? | IDENTITY 是标准,SERIAL 是扩展 |
| 事务回滚后 ID 会回退吗? | 不会 |
| 如何插入指定 ID? | OVERRIDING SYSTEM VALUE |
| 如何查看当前序列值? | SELECT last_value FROM seq_name |
十六、迁移对照表(MySQL → PostgreSQL)
| MySQL | PostgreSQL |
|---|
| AUTO_INCREMENT | GENERATED ALWAYS AS IDENTITY |
| INT AUTO_INCREMENT PRIMARY KEY | INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY |
| BIGINT AUTO_INCREMENT | BIGINT GENERATED ALWAYS AS IDENTITY |
| INSERT IGNORE | ON CONFLICT DO NOTHING |
到此这篇关于PostgreSQL AUTO INCREMENT(自动增长) 的使用的文章就介绍到这了,更多相关PostgreSQL AUTO INCREMENT内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!