迁移运维进阶:migrate diff、squash 与 db execute
本教程共 54 篇 · 第 34 篇 · 更新于 2026-08-11 · 约 6 分钟阅读
本节目标:掌握迁移运维三件套——
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 新增)
Warningv7 破坏性变更:
--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
Notev7 中
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 的时机在升级之前——先有后悔药,再动手术。
NotePrisma 不会自动执行 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 保证它排序在第一位,新环境重放时一步到位。
Warningsquash 会丢弃手写进迁移文件的自定义 SQL(触发器、视图等),压完记得补回来。操作前确认所有环境的迁移都已应用,否则 checksum 对不上会引发历史冲突。
squash 不是日常操作。历史超过几十条、重放时间明显变长,或者要给新环境「减负」时才值得做,频率一年一两次就够。每次操作前后都备份迁移目录。
热修复:直接改生产库后对齐历史
线上慢查询,DBA 直接在生产库加了个索引。这是没走迁移的改动,会让库与迁移历史漂移。对齐流程:
- 把同样的改动写进 Schema(加
@@index) - 本地
npx prisma migrate dev --name retroactively-add-index生成迁移 - 不执行 deploy,直接
npx prisma migrate resolve --applied <迁移名>在打过补丁的库上标记已应用 - 提交迁移文件,其他没打过补丁的环境由 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.ts 的 datasource.url,绕过 PgBouncer。
Tip排障第一原则:先
migrate status看清账本,再动手。大多数「迁移卡住」只是账本和库不一致,而不是库坏了。
参考来源
- Prisma 官方文档:migrate diff
- Prisma 官方文档:db execute
- Prisma 官方文档:Generating down migrations
- Prisma 官方文档:Squashing migrations
- Prisma 官方文档:Patching and hotfixing
- Prisma 官方文档:Troubleshooting