本文目录导读:

是的,在 Laravel 中分析数据库索引性能时,强烈建议使用 explain 方法。
Laravel 的查询构建器(Query Builder)和 Eloquent ORM 都原生支持生成 EXPLAIN 语句,帮助你分析 SQL 执行计划,判断索引是否被有效使用。
如何在 Laravel 中使用 Explain
Laravel 提供了 explain() 方法,可以直接链式调用:
// 原始查询
$sql = DB::table('users')
->where('email', 'like', '%@gmail.com')
->toSql();
// 获取 Explain 结果
$explain = DB::table('users')
->where('email', 'like', '%@gmail.com')
->explain();
dd($explain); // 输出索引使用情况
如果你是用的 Eloquent 模型:
$explain = User::where('status', 'active')
->orderBy('created_at', 'desc')
->explain();
dd($explain);
注意:
explain()返回的是一个集合(Collection),每条记录对应一个执行计划行(如果是复杂查询可能有多个表)。
Explain 结果关键字段解读(特别注意索引相关)
| 字段 | 含义 | 索引相关判断 |
|---|---|---|
type |
访问类型(性能从好到差) | const / eq_ref / ref / range 表示用到了索引;ALL 表示全表扫描(最差) |
possible_keys |
可能用到的索引 | 列出了可选的索引 |
key |
实际使用的索引 | 如果为 NULL,表示没有使用索引 |
key_len |
使用的索引长度 | 越短越好,但复合索引要看是否用到了前缀 |
rows |
扫描的行数 | 行数越少,索引效率越高 |
Extra |
额外信息 | Using index(覆盖索引)、Using where(回表)、Using filesort(未用索引排序,危险) |
典型好索引 vs 坏索引示例
| 查询 | type |
key |
rows |
|
|---|---|---|---|---|
WHERE id = 1 |
const |
PRIMARY |
1 | ✅ 最好 |
WHERE email = 'test@test.com' |
ref |
users_email_unique |
1 | ✅ 好 |
WHERE age > 18 |
range |
idx_age |
1000 | ⚠️ 可接受 |
WHERE name LIKE '%张三%' |
ALL |
NULL |
100万 | ❌ 全表扫描 |
ORDER BY created_at 无索引 |
ALL + Using filesort |
NULL |
100万 | ❌ 最差 |
实际调试示例:发现问题 + 添加索引
问题场景
// 查询未使用索引
$users = DB::table('users')
->where('last_login', '>', now()->subDays(30))
->orderBy('created_at')
->get();
// 执行 explain
$explain = DB::table('users')
->where('last_login', '>', now()->subDays(30))
->orderBy('created_at')
->explain();
Explain 结果:
type:ALL(全表扫描)key:NULLExtra:Using where; Using filesort(未用索引排序)
解决方案:添加复合索引
// 迁移文件
Schema::table('users', function (Blueprint $table) {
$table->index(['last_login', 'created_at'], 'idx_last_login_created');
});
explain 后:
type:rangekey:idx_last_login_createdrows: 大幅减少Extra:Using where; Using index(排序也通过索引完成)
调试工具与扩展
1 Laravel Debugbar
安装 barryvdh/laravel-debugbar,可以直接在浏览器底部看到每条 SQL 的 Explain 执行计划(需在配置中启用 explain 功能)。
2 全局记录慢查询 + Explain
// AppServiceProvider 的 boot 方法
DB::listen(function ($query) {
if ($query->time > 1000) { // 超过1秒
$explain = DB::select("EXPLAIN " . $query->sql, $query->bindings);
Log::channel('slow_sql')->info('Slow query explain:', [
'sql' => $query->sql,
'explain' => $explain,
]);
}
});
3 Tinker 交互式调试
php artisan tinker
> $explain = DB::table('orders')->where('total', '>', 100)->explain();
> $explain->toArray();
常见索引问题 + Explain 特征
| 问题 | Explain 特征 | 解决方案 |
|---|---|---|
| 全表扫描 | type: ALL, key: NULL |
添加合适的单列或复合索引 |
| 索引列参与函数运算 | type: ALL, Extra: Using where |
改为 WHERE date(created_at) = '...' → WHERE created_at >= '...' AND created_at < '...' |
| 模糊查询以 开头 | type: ALL, key: NULL |
考虑全文索引或搜索引擎 |
| 复合索引前缀缺失 | type: ref/key: idx_a_b 但只用了 a |
调整查询顺序或重建复合索引 |
| 排序未用索引 | Extra: Using filesort |
添加排序字段到索引末尾 |
总结建议
- 任何可能导致慢查询的地方(
where、orderBy、join、groupBy)都跑一次explain()。 type出现ALL或Extra出现Using filesort是主要优化目标。- 不要只看
key不为空,还要看type和rows。type=index(全索引扫描)比type=ALL好不了太多。 - 索引不是越多越好——通过 explain 确认每个索引确实被用到,删除冗余索引。
一句话:在 Laravel 中,用 ->explain() 查看执行计划是索引优化的第一步,也是最重要的一步。