Laravel Eloquent orm的性能 - N+1 查询问题

2023-06-01 00:00:00 laravel eloquent 性能

我知道这个问题 N+1 是影响我项目性能的问题之一,我发现这篇文章包含了原因 

https://laravel-news.com/laravel-n1-query-problems 

和解决方案 问题,我想和你分享,因为这个话题很重要

四个案例明确问题并解决问题


案例 1.“常规”N+1 查询

// app/Models/Book.php
class Book extends Model
{
    public function author()
    {
        return $this->belongsTo(Author::class);
    }
}
// Then, in some Controller:
$books = Book::all();
foreach ($books as $book) {
    echo $book->author->name;
}

固定

// Instead of
$books = Book::all();
// You should do
$books = Book::with('author')->get();


案例 2. 两个重要符号

public function index()
{
    $authors = Author::with('books')->get();
    return view('authors.index', compact('authors'));
}
// Blade
@foreach($authors as $author)
    <tr>
        <td>{{ $author->name }}</td>
        <td>{{ $author->books()->count() }}</td>
    </tr>
@endforeach

因此,关系方法将为每个作者查询数据库。 但是如果你加载数据,不带 () 符号,它会成功使用急切加载的数据 $author->books

使固定

// Controller
$authors = Author::withCount('books')->get();
// Blade
{{ $author->books_count }}


案例 3. Accessor 中的“隐藏”关系

// Controller
public function index()
{
    $authors = Author::all();
    return view('authors.index', compact('authors'));
}
// Blade
@foreach($authors as $author)
    <tr>
        <td>{{ $author->name }}</td>
        <td>{{ $author->is_active ? 'Yes' : 'No' }}</td>
    </tr>
@endforeach
“is_active”是在 Eloquent 模型中定义的
use Illuminate\Database\Eloquent\Casts\Attribute;
class Author extends Model
{
    public function isActive(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->books->count() > 0,
        );
    }
}


案例 4. 小心 with Packages

Laravel 有一个很棒的软件包生态系统,但有时“盲目地”使用它们的功能是很危险的。 如果您不小心,您可能会遇到意外的 N+1 查询。

针对 N+1 查询的内置解决方案

从 Laravel 8.43 开始,框架 

https://laravel-news.com/disable-eloquent-lazy-loading-during-development

除了 Laravel Debugbar 进行检查,还可以添加代码来预防这个问题

需要在 

app/Providers/AppServiceProvider.php 

添加两行代码

use Illuminate\Database\Eloquent\Model;
class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Model::preventLazyLoading(! app()->isProduction());
    }
}

现在,如果您启动任何包含 N+1 查询问题的页面,您将看到一个错误页面

我只解释了重点,但要深入,必须增加文章并从中受益。


转:

https://dev.to/morcosgad/eloquent-performance-n1-query-problems-laravel-5ahj

相关文章