mysql-migration 技能设计理念¶
mysql-migration 是一个 MySQL schema 迁移安全审查和 DDL 生成技能。其核心理念是:MySQL DDL 锁行为依赖版本和操作类型,这种依赖关系并不直观,而错误的后果极为严重。一张 5000 万行的生产表上 30 秒的锁就会造成服务中断。这个技能的存在正是为了防止这种情况。
1. 定义¶
mysql-migration 是一个结构化的 MySQL DDL 安全审查技能。它首先收集上下文(版本、行数、拓扑),然后选择审查深度和操作模式,再逐条应用 DDL 安全清单,最后通过 §9 输出契约产生输出——上下文门控、风险评估表、执行计划、迁移 SQL、验证 SQL、回滚计划、上线后检查和未覆盖风险这些章节始终存在。
2. 背景与问题¶
MySQL DDL 安全有一套特定的失败模式。大多数 schema 迁移导致的生产事故都落入以下五类:
| 失败模式 | 后果 |
|---|---|
| 算法错误——本可用 INPLACE 却触发了 COPY | 大表上 30-90+ 分钟的全排他锁 |
| 批量 ALTER 混合算法 | 本可 INSTANT 的 ADD COLUMN 因与类型变更批合并而被静默降级为 COPY |
| 缺少 session guards | DDL 无限排队,级联导致连接池耗尽 |
| 有存量 NULL 的列添加 NOT NULL | ALTER 在全表扫描后失败;COPY 已在进行中 → 数分钟的回滚锁 |
| gh-ost 跳过演练直接上线 | 迁移在未验证连接、用户权限或 schema 状态的情况下启动 |
技能系统性地解决了这些问题。它解决的不是"没人懂 SQL"的问题——而是"我知道想做什么"和"我确切知道会执行哪种算法、是否需要工具"之间的鸿沟。
3. 为什么是四个强制门控?¶
门控 2(模式:审查/生成/规划)和门控 4(完整性检查)用于界定范围并防止输出不完整。关键设计决策集中在门控 1 和门控 3 上。
门控 1(上下文收集) 解决了迁移错误最常见的根源:在不知道版本和行数的情况下给出建议。技能在给出建议前收集 8 项上下文信息。当信息缺失时,它不是拒绝服务——而是记录假设(始终保守:5.7、高流量、source-replica)后继续处理。这就是降级模型——优雅降级,而非沉默。
门控 3(风险分类) 增加了一个硬性阻断:任何没有缓解方案的 UNSAFE 项都会阻止输出完成。这防止了技能把"使用 gh-ost"作为脚注处理,而主要输出还在描述原生 ALTER。缓解措施必须在输出完成前存在。
4. 算法矩阵作为外部参考¶
DDL 算法矩阵在 references/ddl-algorithm-matrix.md 中,而不是内联在 SKILL.md 里。这是一个有意为之的设计选择。
该矩阵较大(跨 MySQL 5.7 和 8.0 的 80+ 操作行,附有注释)。内联会使 SKILL.md 过长,难以快速推理。更重要的是,算法矩阵是一个查找表,而不是推理逻辑——它告诉你服务器会做什么,但技能的工作是决定你应该做什么以及为什么。分离使 SKILL.md 专注于过程(何时查阅以及如何处理结果),而参考文件保持专注于事实。
同样的逻辑适用于 large-table-migration.md:gh-ost 命令模板、5 阶段执行模式和批次大小规则按需加载(深度模式或 >1000 万行),而非始终存在。
5. 降级模式设计¶
MySQL 迁移在一种特定的降级上下文中失败:工程师知道目标 schema 变更,但不知道当前表大小或确切的 MySQL 版本。这在实践中很常见——有人在没有数据库访问权限的情况下审查同事的迁移文件。
技能定义了四种操作模式(Full/Degraded/Minimal/Planning),并将每种模式映射到一组能力和约束。关键规则:
- 没有证据不声称 SAFE。 在 Degraded/Minimal 模式下,每个 SAFE 判定都有限定:"SAFE(假设——请在生产环境验证)"。
- 版本未知时假设 5.7(最严格)。 这防止了仅在 8.0.12+ 上有效的 INSTANT 建议。
- 明确命名模式。 明确声明"DEGRADED MODE ACTIVE"很重要,因为它为整个输出设定了读者预期——每个结论都是条件性的。
评估证实了这一点的重要性:在不使用技能的情况下,基准 Claude 在未知版本审查的响应中暗示 INSTANT 可能在 5.7 上可用(事实并非如此)。降级规则防止了这类错误。
6. INSTANT 边界陷阱(utf8mb4 VARCHAR 扩展)¶
有一个特定的边界场景难度足够高,值得在设计理念中单独说明:utf8mb4 下跨越 255 字节存储边界的 VARCHAR 扩展。
MySQL 根据字节大小不同地存储 VARCHAR 的长度前缀: - ≤255 字节:1 字节长度前缀 - >255 字节:2 字节长度前缀
使用 utf8mb4(最大 4 字节/字符)时:VARCHAR(60) = 240 字节(≤255,1 字节前缀),VARCHAR(100) = 400 字节(>255,2 字节前缀)。跨越这个边界需要 COPY 算法——因为行格式发生了变化,INPLACE 和 INSTANT 都不可用。这会误导那些应用"VARCHAR 扩展很快"规则但没有考虑编码特定字节阈值的工程师。
技能在 DDL 算法矩阵参考和 §7 反例中都编码了这一点。评估证实基准 Claude 可以独立发现这个问题——但矩阵和清单项 5.1.1 确保它总是被捕获,而不只是偶尔。
7. §9 输出契约¶
输出契约是技能的完整性门控。其九个必需章节的存在是因为每个都防止一种特定的失败:
| 章节 | 防止的失败 |
|---|---|
| §9.1 上下文门控 | 给出建议但未声明假设——事后无法验证正确性 |
| §9.3 风险评估表 | 未显式标记每条操作的风险——审查者无法扫描 UNSAFE |
| §9.4 执行计划 | "直接运行 ALTER" 无分阶段——无法将 INPLACE 安全操作与需要 COPY 的操作分离 |
| §9.5 含 guards 的迁移 SQL | 缺少 session guards——MDL 争用下 DDL 无限排队 |
| §9.7 回滚计划 | 没有回滚——在没有文档化恢复路径的情况下做出不可逆变更 |
| §9.9 未覆盖风险 | 已知未知数不可见——审查者假设完整性而上下文实际缺失 |
§9.9(未覆盖风险)有一个特殊规则:它永远不能为空。即使在完整上下文的 Full 模式下,也总存在残留未知数(锁期间的应用行为、跨 schema 的外键链、副本上的 binlog 格式)。强制其存在使输出对静态审查的局限性保持诚实。
评分卡(附在 §9.9 之后):12 分评分结构(Critical 3/Standard 5/Hygiene 4)作为审查的最终判定。它将叙述性分析转化为可在代码审查时强制执行的二元通过/失败:"Critical 失败意味着该迁移不能按原样部署。"
8. 与常见替代方案的比较¶
| 维度 | mysql-migration 技能 | 不带技能的通用模型 | 静态 linter(pt-audit 等) |
|---|---|---|---|
| DDL 算法准确性 | 强(矩阵 + 清单) | 中(通常正确,边界场景易混淆) | 弱(仅 schema,无版本感知) |
| 大表检测 | 强(>1000 万触发工具推荐) | 中(因请求而异) | 弱 |
| 降级模式 | 强(命名、明确) | 弱(静默假设) | 不适用 |
| session guard 强制执行 | 强(Critical 清单项) | 弱(不总是检查) | 不适用 |
| 输出结构 | 强(§9 契约) | 弱(随请求变化) | 结构化但范围窄 |
| 回滚规划 | 强(分阶段) | 弱(仅叙述) | 不适用 |
| 误声明防止 | 强(无证据不声称 SAFE) | 中 | 不适用 |
9. 未采纳的设计决策¶
非触发式技能(无触发准确率指标):与需要决定是否激活的审查技能不同,mysql-migration 总是被显式调用。它不需要区分"这是迁移审查"和"这是别的什么"——用户是有意调用它的。
非仅 pt-osc 技能:早期草案倾向于专门使用 pt-osc。gh-ost 被推荐为默认方案,因为它使用 binlog 流(无触发器),支持通过 socket 暂停/恢复,并内置副本延迟限速。对于有外键约束的表(gh-ost 无法处理入向 FK),pt-osc 有说明。技能不将工程师锁定在单一工具上。
非单文件技能结构:SKILL.md 正文约 280 行,在 420 行预算内。参考文件按需加载。这避免了技能过长难以快速扫描但又过短不够实用的陷阱——技能正文是推理逻辑,参考文件是查找表。