应在迁移中加索引仅当up()明确需加速的查询路径已存在,且字段用于where、join、order by或group by;高频字段、外键、复合条件需建索引,避免重复声明同一字段索引,联合索引须按最左前缀和查询实际顺序合理设计。

Hyperf 迁移中创建索引不是“加了就行”,关键看字段选择、顺序、类型和是否真正被查询用到;不加可能慢,乱加反而拖垮写性能。
什么时候该在迁移里加索引?
只在以下情况才值得加:up() 中明确需要加速的查询路径已存在,且该字段出现在 WHERE、JOIN、ORDER BY 或 GROUP BY 中。别为“以后可能用到”提前加。
- 高频查询字段(如
user_id、email、status) - 复合查询条件(如同时查
category_id和created_at)→ 考虑联合索引 - 外键字段(
account_id)默认应建索引,否则JOIN会全表扫描 - 主键字段自动有
PRIMARY KEY索引,无需额外声明
$table->unique() 和 $table->index() 别混用同一字段
这是 Hyperf 迁移里最常踩的坑:同一个字段调两次索引方法会报错或生成冗余 SQL。
-
$table->string('email')->unique();→ 自动建唯一索引,名字由框架生成(如users_email_unique) -
$table->unique('email', 'idx_users_email');→ 显式指定索引名,效果等同上,但更可控 - 两者不能共存:如果写了
$table->string('email')->unique(),再写$table->index('email'),迁移会失败或产生冲突 - 联合索引必须用数组传参:
$table->index(['user_id', 'created_at'], 'idx_user_created');
联合索引顺序怎么排?
MySQL 遵循最左前缀匹配,顺序错了索引就废了一半。
- 把区分度高的字段放前面(比如
user_id比status更离散) - 按实际查询条件排序:如果常见查询是
WHERE status = ? AND user_id = ?,那索引应是['user_id', 'status'],而不是反过来 - 避免只用后半段字段查:索引
['a', 'b', 'c']对WHERE b = ? AND c = ?无效 - 如果还要支持
ORDER BY created_at DESC,且查询含WHERE user_id = ?,可建['user_id', 'created_at']覆盖索引
迁移执行前必须检查的三件事
很多死锁和慢查询,其实源于迁移没做防御性判断。
- 先确认表是否存在:
if ($this->schema->hasTable('users')) { ... },避免重复建表报错SQLSTATE[42S01] - 不要在迁移里加函数索引(如
UPPER(email)),Hyperf 当前版本不支持,会直接抛异常 - 批量插入前删掉非必要索引,插入完再加回来——特别是百万级初始化数据时,能省掉 80% 写入时间
索引不是越多越好,而是越准越好;Hyperf 迁移文件里每一条 index() 或 unique() 都得对应一个真实、高频、未优化的查询路径,否则它只是在 silently 拖慢你的 INSERT/UPDATE。











