关于 db-migration-safety
db-migration-safety 是在迁移执行前检查 SQL 或 ORM 迁移文件的静态审查技能,供迁移审计器和编写 Agent 使用。它关注回滚能力、锁、表重写、破坏性操作及模式漂移,只提出修复建议,不执行迁移。
主要功能
- 01检查回滚方案与扩展-收缩流程
- 02识别阻塞锁和全表重写风险
- 03标记破坏性操作与非空约束问题
- 04检查枚举变更和模式漂移
- 05提供安全改写及验证方法
适用场景
- 01执行前审查数据库迁移文件
- 02发现可能阻塞热表的 SQL
- 03为非空字段变更规划数据回填
- 04检查迁移历史与模式定义是否一致
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ hainrixz/ claude-db --skill db-migration-safety安装后在 Claude Code 中输入/db-migration-safety确认已加载。
详细介绍
db-migration-safety (M22) — 迁移 lint 契约
M22 会在执行候选迁移前,将其作为静态产物进行 lint。migration-safety auditor 和 db-migration-writer Agent 都遵循此契约。为 Performance & Scale(Almacenamiento/operability 类别)提供数据。具有破坏性且不可逆的迁移,在性能轴上的严重程度上限为 sev-5。
检查内容(lint 契约)
- 可逆性 — 存在可用的
down/回滚,或变更遵循 expand-contract(在不同部署中依次执行 add-new → backfill → switch → drop-old)。没有down的一次性破坏性步骤,是此处严重程度最高的问题。 - 锁级别 — 语句是否会对热点表加阻塞锁?在 Postgres 中:添加带有易变默认值的列(11 之前)、
ALTER COLUMN TYPE、添加不带NOT VALID的CHECK/FK、创建非CONCURRENTLY索引,都会获取ACCESS EXCLUSIVE锁/阻塞写入。优先使用CREATE INDEX CONCURRENTLY、ADD CONSTRAINT ... NOT VALID,然后执行VALIDATE CONSTRAINT。 - 表重写 — 导致整张表重写的变更(某些
ALTER COLUMN TYPE、旧版本引擎上添加带易变默认值的NOT NULL列)→ 在大表上耗时且长时间持锁。 - 破坏性操作 —
DROP COLUMN、DROP TABLE、TRUNCATE、撤销DROP NOT NULL、删除仍被已部署代码读取的列。破坏性操作且不可逆 = sev 5(性能严重程度上限)。 - 添加到已有数据表的
NOT NULL列没有默认值 → 会失败或加锁;必须提供回填计划。 - 枚举变更 — 长期需要关注的问题:枚举值无法移除或重新排序(不支持移除;重命名/重新排序会破坏依赖项),因此,取值会变化的集合应使用查找表,而不是原生枚举。
ALTER TYPE ... ADD VALUE只能追加,并且在 PG12+ 中可在事务内执行(只有更早版本的 PG 禁止在事务中执行)。标记枚举变更;建议使用查找表。 - 架构漂移 — 声明式产物(schema.prisma / structure.sql / snapshot)与迁移历史不一致(某列只存在于其中一方)→ 发出方向性警告。
Tier-0 静态检查
解析迁移 SQL/ORM 迁移文件(scripts/parse-schema.mjs、parse-orm-python.py)。扫描以下内容:
DROP TABLE|DROP COLUMN|TRUNCATE;ALTER COLUMN .* TYPE;不带 DEFAULT 的 ADD COLUMN .* NOT NULL;缺少 CONCURRENTLY 的 CREATE INDEX;缺少 NOT VALID 的 ADD CONSTRAINT(FK/CHECK);ALTER TYPE .* ADD VALUE/枚举值移除或重新排序;缺少 down/回滚代码块;权威产物(references/detection-signals.md 中的优先级)与最新迁移之间的漂移。
Tier-1 验证查询
- 受影响表的大小(锁是否会造成影响?):
SELECT pg_size_pretty(pg_total_relation_size('<t>')), reltuples FROM pg_class WHERE relname='<t>'; - 语句将获取的锁:检查
EXPLAIN/pg_locks,或针对一次性副本/影子 DB 执行dry_run_migration。影子 DB 可用时,使用verification.method: dry_run_migration;否则对静态 SQL 执行migration_lint。若需要实时数据大小来判断严重程度,但无法连接数据库 → 标记为needs_api,绝不能静默通过。
检查结果
按 schema/finding.schema.json 输出。示例 ID:
M22.20240115_drop_users_legacy.destructive_irreversible— 执行DROP COLUMN,没有 down 且列仍被引用(失败,严重级别 5,轴performance,可修复性proposed→ 扩展-收缩方案)。M22.add_index.lock_blocking— 在高频使用的表上执行CREATE INDEX,但未使用CONCURRENTLY(警告,严重级别 4,轴performance,可修复性auto→ 添加CONCURRENTLY)。M22.add_email_notnull.notnull_no_default— 在已有数据的表上执行ADD COLUMN ... NOT NULL,但没有默认值(失败,严重级别 4,轴performance,可修复性proposed)。M22.status_enum.enum_value_removed— 枚举值被删除或重新排序(不支持;会破坏依赖项)— 建议改用查找表(警告,严重级别 3,轴performance)。M22.drift.column_in_artifact_not_migration— 架构漂移(警告,严重级别 2,轴performance,置信度directional)。 每项检查结果:evidence.observed引用违规迁移语句的原文(已 redact 密钥);verification.reproduce是上文中使用$DATABASE_URL的可运行命令;verification.method为migration_lint或dry_run_migration;fix_preview包含更安全的改写(例如CONCURRENTLY、NOT VALID+VALIDATE、扩展-收缩序列);expected_impact包含{axis, confidence, magnitude, rationale}— 采用分档表示,绝不使用单一百分比。
诚实原则
- 锁的严重程度取决于表大小和写入速率 — 没有实时证据时,对于大小未知的表,阻塞操作的严重程度为
directional(中等),而不是已确认的严重级别 5。不要声称停机时长精确到秒;只能使用分档表示影响程度。 - 只有
DROP/TRUNCATE类破坏性且不可逆的迁移,才会将性能严重级别设为 5。可逆或扩展-收缩变更属于警告。漂移仅为方向性,绝不会将严重级别设为上限。 - 只读:M22 只执行检查并提出建议,绝不执行迁移。迁移由写入 Agent 负责,且须经用户明确接受。
评论
支持 Markdown