laravel 迁移中用 $table->index() 或 $table->unique() 添加索引,前者仅加速查询,后者强制唯一约束并影响原子操作;复合索引需等值字段在前、范围字段在后;慎用 fulltext(仅限 match against);大表加索引应选低峰期或使用 pt-online-schema-change。

MySQL 的 ALTER TABLE ... ADD INDEX 在 Laravel 迁移里怎么写
直接在迁移文件里用 Schema::table() 调用 index() 方法,不是手写 SQL。Laravel 会生成标准的 ALTER TABLE ... ADD INDEX,但底层行为取决于你传的字段和索引类型。
常见错误是只给单字段加索引,却在查询里用了多字段 WHERE 组合(比如 WHERE status = ? AND created_at > ?),结果索引完全没被用上。
- 复合索引顺序很重要:把等值查询字段放前面,范围查询字段(
BETWEEN、>、LIKE 'abc%')放后面 - 别在
nullable字段上盲目加索引——如果大量是NULL,MySQL 可能跳过它 - 用
DB::select('EXPLAIN ...')或php artisan tinker手动执行EXPLAIN SELECT ...看key和rows列是否符合预期
Laravel 的 $table->index() 和 $table->unique() 有什么实际区别
不只是“唯一性约束”和“普通索引”的语义差别,它们生成的 MySQL 索引结构相同,但 unique 会额外触发数据库层校验,且 Laravel 的 exists()、firstOrCreate() 等方法内部可能依赖这个约束做原子操作。
容易踩的坑:把 email 字段设成 unique,但没设 NOT NULL —— MySQL 允许多个 NULL,这时唯一性就失效了;或者在已有数据的表上加 unique,迁移直接报错 SQLSTATE[HY000]: General error: 1062 Duplicate entry '' for key 'users_email_unique'。
- 加
unique前先用DB::table('users')->where('email', '')->count()检查空值 -
index()不阻止重复插入,unique()会抛Illuminate\Database\QueryException(错误信息含1062 Duplicate entry) - 如果只是为加速查询,不用
unique;如果业务逻辑要求不重复(如邮箱、手机号),必须用unique并确保字段NOT NULL
什么时候该用 fulltext 索引而不是普通 index
只有当你真正在用 MATCH() AGAINST() 做自然语言搜索时才需要 fulltext。用 LIKE '%关键词%' 或 WHERE title LIKE '关键词%' 完全用不上它,反而会让索引变大、写入变慢。
MySQL 的 fulltext 对中文支持极弱(5.7 默认只切分英文单词),Laravel 迁移里调用 $table->fullText('content') 后,你还得确认表引擎是 MyISAM 或 InnoDB(5.6+),且字段类型是 TEXT 或 VARCHAR(长度不能超 3072 字符,否则建索引失败)。
- 测试前先在 MySQL 里手动跑
SELECT MATCH(title) AGAINST('laravel' IN NATURAL LANGUAGE MODE) FROM posts;看是否返回非零值 - Laravel 的
whereFullText()是 9.x 新增方法,8.x 只能手写whereRaw("MATCH(title) AGAINST(? IN NATURAL LANGUAGE MODE)", [$q]) - 别在用户 ID、状态码这类离散值字段上加
fulltext——它只会拖慢 INSERT/UPDATE
生产环境加索引为什么卡住,以及怎么安全加
MySQL 5.6+ 的 ALGORITHM=INPLACE 能在线加普通索引,但前提是没用到 ORDER BY、LOCK=SHARED 等限制条件。Laravel 迁移默认不指定这些,所以大表(千万级)加索引仍可能锁表几十秒甚至几分钟。
最常被忽略的一点:Laravel 的 php artisan migrate 是单线程执行,如果迁移里有耗时索引操作,整个部署流程就卡住,而你从日志里只看到 “Running migration: 2023_01_01_000000_add_index_to_posts_table”,根本不知道它在干啥。
- 大表加索引务必在低峰期操作,或改用
pt-online-schema-change工具(Percona Toolkit) - 在迁移文件开头加注释说明该操作影响范围,例如:
// ⚠️ 影响 posts 表约 800 万行,预计耗时 3–5 分钟 - 上线前在预发环境用相同数据量跑一遍迁移,观察
SHOW PROCESSLIST和慢查询日志











