首页 / Prisma ORM 入门教程 / 迁移运维进阶:migrate diff、squash 与 db execute

Prisma ORM 入门教程

迁移运维进阶:migrate diff、squash 与 db execute

本教程共 54 篇 · 第 34 篇 · 更新于 2026-08-11 · 约 6 分钟阅读

Prisma迁移migrate diffdb executesquash热修复排障P3014

本节目标:掌握迁移运维三件套——migrate diff 任意对比、db execute 直连执行、squash 压缩历史,以及热修复与常见排障。

migrate diff:任意两处结构对比

migrate diff 把任意两个「结构来源」做对比,输出从一个变成另一个所需的 SQL。来源可以是:

  • --from-empty / --to-empty:空库
  • --from-schema / --to-schema:Schema 文件
  • --from-migrations / --to-migrations:迁移历史目录
  • --from-config-datasource / --to-config-datasource:配置文件里的真实数据库(v7 新增)
Warning

v7 破坏性变更:--from-url--to-url--from-schema-datasource 等旧旗标已移除,一律改用 --from-config-datasource 系列。数据库连接从 prisma.config.ts 读取,不再从旗标传入。

对比的两端必须用同一种数据库厂商:PostgreSQL 的 Schema 不能和 MySQL 的迁移历史对比。SQLite 没有影子数据库的概念,涉及迁移历史的对比会自动用临时文件代替。

典型用法——对比迁移历史和真实数据库,检查库是否漂移:

npx prisma migrate diff \
  --from-migrations prisma/migrations \
  --to-config-datasource \
  --script

默认输出给人看的人类可读摘要;加 --script 输出可执行的 SQL;加 --exit-code 时,检测到差异退出码为 2,可以写进 CI 当一致性检查。

db execute:绕过账本执行 SQL

db execute 直接对数据库执行 SQL 脚本,不碰迁移表:

npx prisma db execute --file ./script.sql
echo 'TRUNCATE TABLE dev;' | prisma db execute --stdin

--file--stdin 二选一。它和 migrate deploy 的配合场景:迁移失败后,先用 migrate diff 生成修复 SQL,再用 db execute 手工应用,最后 resolve 对齐账本。甚至可以直接管道串联:

npx prisma migrate diff \
  --from-config-datasource \
  --to-schema prisma/schema.prisma \
  --script | prisma db execute --stdin
Note

v7 中 db execute--url 旗标已移除。要对生产库执行,把生产连接字符串配进 prisma.config.ts(或单独的 prisma.config.prod.ts),用 --config 指定。

down migrations:反向迁移

给迁移配一份反向 SQL(down migration),可以在升级失败时手动还原结构。用 migrate diff 反向对比生成:

npx prisma migrate diff \
  --from-schema prisma/schema.prisma \
  --to-migrations prisma/migrations \
  --script > down.sql

down.sql 放进对应迁移目录。升级失败时先 db execute --file down.sql 还原结构,再 migrate resolve --rolled-back <迁移名> 标记回滚。生成 down migration 的时机在升级之前——先有后悔药,再动手术。

Note

Prisma 不会自动执行 down migration,也不会用它做自动回滚。它只是你手里的一张「后悔药」,用不用、何时用由你决定。数据层面的改动(比如回填脚本)不会随 down migration 还原。

压缩历史:squash

迁移历史会越来越长,重放越来越慢。squash 把一堆迁移压缩成一个。两个场景:

开发分支:功能分支上产生的多个中间迁移,合并成一个再进主分支。先重置本地迁移历史到主分支状态,再 npx prisma migrate dev --name squashed_migrations,生成的单文件就是分支的全部改动。

生产收编:把全部历史压成一条。清空 prisma/migrations/,新建 000000000000_squashed_migrations/migration.sql,用 migrate diff --from-empty --to-schema 生成全量 SQL,最后 resolve --applied 标记已应用。前缀全 0 保证它排序在第一位,新环境重放时一步到位。

Warning

squash 会丢弃手写进迁移文件的自定义 SQL(触发器、视图等),压完记得补回来。操作前确认所有环境的迁移都已应用,否则 checksum 对不上会引发历史冲突。

squash 不是日常操作。历史超过几十条、重放时间明显变长,或者要给新环境「减负」时才值得做,频率一年一两次就够。每次操作前后都备份迁移目录。

热修复:直接改生产库后对齐历史

线上慢查询,DBA 直接在生产库加了个索引。这是没走迁移的改动,会让库与迁移历史漂移。对齐流程:

  1. 把同样的改动写进 Schema(加 @@index
  2. 本地 npx prisma migrate dev --name retroactively-add-index 生成迁移
  3. 不执行 deploy,直接 npx prisma migrate resolve --applied <迁移名> 在打过补丁的库上标记已应用
  4. 提交迁移文件,其他没打过补丁的环境由 CI 正常应用

resolve --applied 之前,务必确认生产库的结构和迁移文件描述的一致,否则账本记了假账,后续迁移会在错误的基础上执行。

判断「该不该热修复」的标准:改动是否紧急、且无法等待正常发布流程?如果不是,走常规迁移更安全。热修复留下的历史裂痕需要手工对齐,次数多了账本会很难看。

resolve 的两副面孔:--applied 说「这条已经跑过了」(基线化、热修复都用它);--rolled-back 说「这条不算数,可以重跑」。

常见排障

P3014:影子数据库创建失败(权限不足或云环境不允许建库,配 shadowDatabaseUrl 解决)。P3019:迁移历史与配置文件里的 provider 不匹配(想换数据库厂商,需清空历史重新开始;部分旧文档写作 P3014)。

迁移失败:常见原因有手改迁移引入语法错误、给有数据的表加 NOT NULL 列、迁移中途断连。开发环境直接重置重来;生产环境按第 31 章的 status → diff → execute → resolve 流程处理。失败详情存在 _prisma_migrations 表的 logs 列里。

找不到迁移目录migrate deploy 报找不到 prisma/migrations,说明迁移历史没提交进版本库,或 CI 没拉取。先检查仓库里有没有这个目录。

PgBouncer 报错prepared statement "s0" already exists,说明迁移命令走了连接池。迁移要走直连:把直连地址配进 prisma.config.tsdatasource.url,绕过 PgBouncer。

Tip

排障第一原则:先 migrate status 看清账本,再动手。大多数「迁移卡住」只是账本和库不一致,而不是库坏了。

参考来源

  • Prisma 官方文档:migrate diff
  • Prisma 官方文档:db execute
  • Prisma 官方文档:Generating down migrations
  • Prisma 官方文档:Squashing migrations
  • Prisma 官方文档:Patching and hotfixing
  • Prisma 官方文档:Troubleshooting