N+1 是 Laravel 应用层问题,源于 Eloquent 未预加载关联导致重复 SQL 请求;需通过 Telescope 或 DB::enableQueryLog 定位具体 PHP 代码,用 with()、load() 或禁用懒加载修复,而非数据库优化。
n+1 不是数据库层面的问题,phpmyadmin 无法修复它——它发生在 laravel 应用层,是 eloquent 查询未预加载导致的重复 sql 请求。你在 phpmyadmin 里看到的只是单条 sql 执行结果,根本看不到“n 次重复查询”这个行为本身。
你真正要做的,是在 Laravel 代码里定位并修正关联加载方式,而不是改表结构或执行某条 SQL。
怎么确认是 N+1 而不是数据库慢?
别靠 phpMyAdmin 的“SQL 查询时间”判断。N+1 的典型表现是:页面加载慢、日志里出现大量结构高度相似的 SELECT(比如反复查 users 表的同一字段),且这些查询在 Laravel 日志或 Laravel Telescope 中能清晰归因到某个 Resource 或 Controller 方法。
- 打开 Laravel 的
APP_DEBUG=true环境,访问对应页面,看浏览器开发者工具 Network 标签页的 XHR 请求响应中是否含大量重复 SQL(Telescope 面板更直观) - 检查 Nova Resource 的
fields()方法里有没有写BelongsTo::make('User')->resolveUsing(...)这类手动查模型的逻辑——这几乎必然触发 N+1 - 运行
php artisan tinker,手动执行对应查询链,用DB::enableQueryLog()+dd(DB::getQueryLog())数一数实际发了多少条 SQL
为什么在 phpMyAdmin 里“优化索引”救不了 N+1?
加索引只能让每一条 SELECT * FROM users WHERE id = ? 更快,但不能阻止它被调用 100 次。你看到的“慢查询”其实是 100 条快查询叠加的结果。
- 即使
users.id有主键索引,100 次单行查询仍比 1 次IN (1,2,3,...,100)查询慢得多(网络往返、PHP 解析、连接开销) - phpMyAdmin 的“索引分析”功能只针对单条语句,对批量重复请求无感知
- 有些 N+1 根源甚至不走数据库(比如在
resolveUsing里 new Model() 后调->name,而 name 是个访问器)
真正该改的 Laravel 代码位置
修复必须落在 PHP 层。常见可修复点:
立即学习“PHP免费学习笔记(深入)”;
- Nova Resource 的
fields():把Text::make('Author Name', function () { return $this->author->name; })改成BelongsTo::make('Author'),并确保对应模型的author()关系已定义 - Controller 的 index 方法:把
Post::all()改成Post::with('user', 'category')->get() - 模型的访问器(
getFooAttribute)里避免调用其他模型关系,尤其不能在循环中用$post->user->name - Resource 的
withCount()或withSum()要显式声明,否则可能退化为 N+1 计数
复杂点在于:有些 N+1 隐藏在嵌套资源、条件加载或第三方包内部(比如某些 Nova 字段扩展)。必须用 Telescope 或 Query Log 定位到具体哪一行 PHP 代码触发了额外查询,而不是在 phpMyAdmin 里猜。



















