hyperf migrate 命令变慢主因是反复扫描解析大量迁移文件并逐条查询 migration 表,解决方法为归档历史文件减少扫描量,并为 migration 字段添加 b-tree 索引加速状态判定。

Hyperf 的迁移文件加载本身不慢,慢的是 migrate 命令反复扫描整个 migrations/ 目录、解析每个 PHP 文件并比对已执行记录的过程。直接“合并迁移文件”不能提速,反而破坏幂等性;真正有效的做法是减少待扫描文件数 + 加速已执行状态判定。
为什么 migrate 命令越来越卡?
Hyperf 使用 Hyperf\Database\Migrations\Migrator 扫描 migrations/ 下所有 PHP 文件,逐个 require 并提取 up()/down() 方法签名,再查 migration 表确认是否已执行。当迁移文件超 200 个,尤其是含大量注释或复杂逻辑时,PHP 解析开销明显上升。
- 不是文件体积大导致慢,而是每次命令都重新 require + 反射 + SQL 查询
-
migrate:status比migrate更慢——它要为每个文件都查一次 DB - 开发环境频繁改 migration 后重跑,
migrate:refresh会先 drop 所有表再重放,但扫描步骤仍保留
如何减少迁移文件扫描数量?
核心思路:把历史迁移“归档”,让当前命令只处理增量部分。Hyperf v3.1.60 已支持字符串路径参数,可精准指定范围。
- 将已上线、不再修改的迁移文件移出主目录,例如 mv migrations/2023_* archived_migrations/
- 用
php bin/hyperf.php migrate --path=archived_migrations单独执行归档迁移(仅首次需要) - 日常开发只在
migrations/放新文件,php bin/hyperf.php migrate自动跳过归档目录 - 确保
config/autoload/migrations.php中的'path'配置未硬编码为绝对路径,否则移动后失效
怎么加速已执行状态判定?
默认情况下,每次 migrate 都执行 SELECT * FROM migration WHERE migration = ?。当表中记录超千条,且无索引时,查询变慢。
- 检查
migration表结构:DESCRIBE migration;,确认migration字段有 B-tree 索引 - 若缺失,手动加索引:
ALTER TABLE migration ADD INDEX idx_migration_name (migration); - 避免在生产环境用
migrate:fresh—— 它会 truncate 表再重插全部记录,导致索引重建和锁表 - 开发环境可设
'table' => 'migrations_dev'(在config/autoload/migrations.php中),与生产隔离,避免脏数据干扰
别碰“合并迁移文件”这个念头
有人试图把 50 个 migration 合成 1 个大文件,用 up() 里写 50 个 Db::statement()。这会导致:
-
rollback失效:down() 无法反向拆解原子操作 - 协作冲突:多人同时改同一文件,git merge 极易出错
- 无法按需回退:某次上线发现 bug,想 rollback 到第 42 个迁移,但合并后只剩“第 1 个”
- Hyperf 的
migrate:reset依赖文件名时间戳排序,合并后顺序丢失
真正该合并的是数据库变更逻辑,不是文件本身——比如把连续 3 次 add_column 合并在一个 migration 里,而不是把 30 个无关 migration 堆一起。











