You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中优化代码避免懒加载(解决N+1查询问题)

解决Laravel成绩展示的N+1查询问题

1. 先确认模型关联关系

确保模型间的关联定义准确,这是预加载生效的基础:

Student 模型

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Student extends Model
{
    // 一个学生对应多条成绩记录
    public function grades(): HasMany
    {
        return $this->hasMany(Grade::class);
    }
}

Grade 模型

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Grade extends Model
{
    // 一条成绩属于一个学生
    public function student(): BelongsTo
    {
        return $this->belongsTo(Student::class);
    }

    // 一条成绩对应一门课程
    public function course(): BelongsTo
    {
        return $this->belongsTo(Course::class);
    }
}

Course 模型

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Course extends Model
{
    // 一门课程对应多条成绩记录
    public function grades(): HasMany
    {
        return $this->hasMany(Grade::class);
    }
}

2. 控制器中使用预加载消除N+1

获取登录学生成绩时,用with()方法批量预加载关联的课程数据,Laravel会自动生成带IN条件的SQL一次性查询所有需要的课程,而非循环时逐个查询:

namespace App\Http\Controllers;

use App\Models\Student;
use Illuminate\Support\Facades\Auth;

class GradeController extends Controller
{
    public function index()
    {
        // 假设Auth认证的用户关联了Student模型,根据你的实际调整
        $student = Student::with('grades.course')
            ->find(Auth::user()->student_id);

        // 如果你的Auth用户本身就是Student模型,直接简化为:
        // $student = Auth::user()->load('grades.course');

        return view('grades.index', compact('student'));
    }
}

3. 视图直接使用预加载数据

视图循环成绩时,直接访问$grade->course不会触发新的SQL查询,因为数据已经提前加载完毕:

<h2>{{ $student->name }} 的成绩列表</h2>
<table>
    <thead>
        <tr>
            <th>课程名称</th>
            <th>成绩</th>
        </tr>
    </thead>
    <tbody>
        @foreach($student->grades as $grade)
            <tr>
                <td>{{ $grade->course->name }}</td>
                <td>{{ $grade->score }}</td>
            </tr>
        @endforeach
    </tbody>
</table>

4. 验证优化效果

用Laravel Debugbar查看SQL查询次数,现在只会有3次查询:

  • 1次查询学生信息
  • 1次查询该学生的所有成绩
  • 1次查询所有成绩对应的课程(带IN条件的批量查询)

彻底解决了原来的N+1问题(1次学生查询 + N次成绩查询 + N次课程查询)。

额外说明

如果course_student是学生与课程的多对多中间表,当前场景下不需要用到这个关联——因为成绩已经通过grades表直接关联了学生和课程。如果后续需要查询学生选的所有课程,再在Student模型中补充多对多关联即可:

// Student模型中添加
public function courses(): BelongsToMany
{
    return $this->belongsToMany(Course::class, 'course_student');
}

内容的提问来源于stack exchange,提问作者Zabs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 12:50:21