Eloquent 성능 - N+1 쿼리 문제 - Laravel

저는 이 문제 N+1이 제 프로젝트의 성능에 영향을 미치는 문제 중 하나라는 것을 알고 있었고 이 문제에 대한 이유https://laravel-news.com/laravel-n1-query-problems와 해결책이 포함된 이 기사를 찾았고 그 중요성 때문에 여러분과 공유하고 싶었습니다. 이 주제

문제를 명확히 하고 해결하기 위한 4가지 경우
  • 사례 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. 접근자의 "숨겨진"관계

  • // 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. 패키지 주의

  • 라라벨은 훌륭한 패키지 생태계를 가지고 있지만 때때로 "맹목적으로"그 기능을 사용하는 것은 위험합니다. 주의하지 않으면 예기치 않은 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 쿼리 문제가 포함된 페이지를 시작하면 오류 페이지가 표시됩니다.

    중요한 부분만 설명했지만 더 깊이 들어가려면 기사가 늘어나고 혜택을 받아야 합니다.

    좋은 웹페이지 즐겨찾기