可以,postgresql支持单条insert values语句后接returning *,按values顺序返回每行完整新数据,但需注意表定义、字段顺序、内存开销及并发锁影响。

用 RETURNING * 实现批量 INSERT 并返回完整新行
PostgreSQL 支持在 INSERT 语句末尾加 RETURNING *,直接拿到刚插入的整行数据(含自增 id、默认值、生成列等)。这比先 INSERT 再 SELECT 更安全、更原子。
关键点:必须把多条记录写成单个 VALUES 列表,不能拆成多个 INSERT 语句——否则只有最后一条能被 RETURNING 捕获。
示例:
INSERT INTO users (name, email)
VALUES
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com'),
('Charlie', 'charlie@example.com')
RETURNING *;
执行后会返回三行结果,每行包含数据库实际写入的完整字段(比如 id、created_at 等)。
遇到 RETURNING 只返回部分字段?检查列名和默认值
RETURNING * 看似简单,但实际返回内容取决于表定义。如果某些字段没显式提供值,又没设默认值或 NOT NULL 约束,插入会失败;如果设了默认值(如 created_at TIMESTAMP DEFAULT NOW()),RETURNING * 就会包含计算后的值。
- 确保
VALUES中字段顺序与INSERT INTO ... (col1, col2)显式列出的列完全一致 - 避免依赖隐式列顺序(比如只写
INSERT INTO users VALUES (...)),不同 PostgreSQL 版本或表结构变更时容易出错 - 如果某列是
GENERATED ALWAYS AS (...) STORED,它也会出现在RETURNING *结果里
想按原始输入顺序匹配返回结果?别依赖默认顺序
PostgreSQL 不保证 RETURNING 的行顺序严格等于 VALUES 的书写顺序——尤其在并行插入或有触发器时。若业务需要强对应(比如前端传了数组,要按索引一一绑定返回的 id),得加点辅助手段:
- 在
VALUES中带一个临时序号列:VALUES (1, 'Alice', ...), (2, 'Bob', ...),然后RETURNING seq, id, name - 用
WITH子句配合ROW_NUMBER()构造有序中间集(适合复杂场景) - 不推荐靠应用层“猜顺序”,生产环境容易因并发或优化器行为错位
大批量插入时性能和内存要注意什么
RETURNING 会把所有返回行缓存在内存中,直到客户端逐行取走。插入 10 万行并 RETURNING *,可能瞬间占用几百 MB 内存,还拖慢事务提交速度。
真实压测中常见问题:
- 客户端驱动(如 psycopg2)默认用普通游标,一次性拉取全部结果 → OOM 风险
- 建议改用服务器端游标(
named cursor),分批FETCH - 如果只需要新生成的
id,显式写RETURNING id比RETURNING *节省 50%+ 网络和内存开销 - 单次插入超过 1000 行?考虑分批次(如 500 行/批),平衡原子性与资源压力
最易被忽略的是:很多人以为 RETURNING 是“免费午餐”,其实它让 INSERT 从纯写操作变成了读写混合,锁持有时间变长,高并发下可能成为瓶颈。










