Files
vibe_coding/.cursor/skills/database-migration/references/migration-patterns.md
2026-03-05 21:27:11 +08:00

2.6 KiB
Raw Blame History

Database Migration — 迁移模式与示例

主流程见 SKILL.md本文档为幂等迁移、Expand-Contract、批量迁移、大表策略的完整实现。

幂等迁移

public function up(): void
{
    if (!Schema::hasTable('production_orders')) {
        Schema::create('production_orders', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('order_no', 50)->unique();
            $table->timestamps();
            $table->softDeletes();
        });
    }
    if (!Schema::hasColumn('production_orders', 'priority')) {
        Schema::table('production_orders', function (Blueprint $table) {
            $table->tinyInteger('priority')->default(0)->after('status');
        });
    }
    if (!$this->hasIndex('production_orders', 'idx_orders_priority')) {
        Schema::table('production_orders', function (Blueprint $table) {
            $table->index('priority', 'idx_orders_priority');
        });
    }
}

Expand-Contract 三阶段示例(字段重命名 username → display_name

Phase 1 EXPAND: 添加 display_name nullable。部署 v2 双写。
Phase 2 MIGRATE: 独立迁移文件批量 UPDATE 回填。部署 v3 读新写双。验证一致性。
Phase 3 CONTRACT: 删除 username。部署 v4 仅新字段。

时间线Day 1 加字段+双写Day 2 回填Day 3 读新写双+验证Day 7 删旧字段。

批量数据迁移模板

$batchSize = 2000;
$lastId = 0;
while (true) {
    $affected = Db::update("UPDATE users SET normalized_email = LOWER(email) WHERE id > ? AND normalized_email IS NULL ORDER BY id LIMIT ?", [$lastId, $batchSize]);
    if ($affected === 0) break;
    $lastId = Db::selectOne("SELECT MAX(id) AS max_id FROM users WHERE normalized_email IS NOT NULL AND id > ?", [$lastId])->max_id ?? $lastId + $batchSize;
    usleep(100_000);
}

规则10005000 行/批、批次间 sleep、游标 WHERE id > ?、低峰期执行。

大表变更策略(百万级+

操作 风险 方案
ADD COLUMN 直接执行nullable 或有默认值
ADD INDEX ALGORITHM=INPLACE, LOCK=NONE
DROP COLUMN 先移除代码→部署→下版本迁移删除
ALTER TYPE Expand-Contract
RENAME COLUMN Expand-Contract
DROP TABLE 极高 先重命名→观察一周→删除

危险操作清单

操作 缓解
DROP TABLE 先备份
DROP COLUMN 先移除代码引用
ALTER TYPE Expand-Contract
TRUNCATE 禁止生产
NOT NULL 无默认值 先 nullable→回填→再加约束