Laravel: Могут ли добавления атрибутов привести к проблеме n + 1? - PullRequest
2 голосов
/ 04 марта 2020

Введение
Я начинаю использовать атрибуты добавления в моделях осенью 2019 года. В начале было просто запустить функцию, которая объединит два столбца, но теперь я использую их для некоторого анализа определенные модели, прежде чем отправить его на фронтэнд. Теперь я подозреваю, что это приведет к проблеме n + 1. Итак, давайте проверим некоторое использование атрибутов добавления.

Основы c использование

<?php

namespace App;

class User extends Authenticatable
{
    protected $dates = ['deleted_at'];
    protected $table = 'users';

    protected $appends =
    [
        'full_name',
    ];

    protected $fillable =
    [
        'username',
        'first_name',
        'last_name',
    ];

    getFullNameAttribute()
    {
        return $this->first_name.' '.$this->last_name;
    }
}

Итак, что позволяет добавлять полное имя , мы знаем, что, но под капотом?

$user = User::find($id);

Использование дополнений с вышеупомянутой моделью извлечения практически не имеет значения для любого приложения. Если мы немного рассмотрим sh, что на самом деле происходит?

$users = User::get();

Теперь, запрос к базе данных такой же, как если бы мы ничего не добавляли? Другими словами, происходит ли добавление во время запроса к БД или после? Как бы то ни было, вам нужно полное имя, и если его нет в базе данных или на сервере, вы сделаете это во внешнем интерфейсе, так что это должно произойти в любом случае. Какой из трех является самым быстрым - это вопрос другого.

Немного более сложное использование

namespace App;

class User extends Authenticatable
{
    protected $dates = ['deleted_at'];
    protected $table = 'users';

    protected $appends =
    [
        'full_name',
        'last_post',
    ];

    protected $fillable =
    [
        'username',
        'first_name',
        'last_name',
    ];

    protected $hidden =
    [
        'password',
        'remember_token',
    ];

    public function posts()
    {
        return $this->hasMany('App\Post', 'user_id');
    }

    getFullNameAttribute()
    {
        return $this->first_name.' '.$this->last_name;
    }

    getLastPostAttribute()
    {
        return $this->posts()->last()
    }
}

Теперь очевидно, что если я сделаю $users->get();, это будет привести к проблеме n + 1. Но если я сделаю это $users->with('posts')->get(); У меня проблема с n + 1 или худшая?

Если вы не используете проблему с n + 1
Проблема с n + 1 возникает, когда Вы создаете запрос, который должен будет сделать первоначальный вызов DB и один вызов для каждого объекта в массив. $users->get() получит всех пользователей, а затем, поскольку я добавляю last_post, так как сообщение, где он не получен, будет выполнять вызов БД для каждой из моделей.

Что я хочу знать, это во втором случай $users->with('posts')->get(), когда Laravel добавит last_post, узнает ли он, что в нем уже есть все сообщения? Так что нет необходимости загружать их во второй раз для каждого пользователя?

Ответы [ 2 ]

1 голос
/ 04 марта 2020

Таким образом, этот атрибут будет вызывать n + 1 запросов независимо от того, что вы предварительно загружаете

getLastPostAttribute()
{
    return $this->posts()->last()
}

Получив доступ к posts() в качестве метода, вы создаете новый экземпляр построителя запросов. это с return $this->posts->last(), и тогда вы можете предварительно загрузить ваши отношения posts и избежать лишних запросов

0 голосов
/ 04 марта 2020

Если вы не уверены, что получаете n + 1 выпусков, вам может потребоваться этот замечательный пакет из-под кода beyondcode/laravel-query-detector, который сообщит вам о любых ваших n + 1.

https://github.com/beyondcode/laravel-query-detector

Чтобы исправить ваш n + 1 ...


$users = Users::with(['posts'])->get();


public function getFullNameAttribute()
{
    return $this->first_name.' '.$this->last_name;
}

public function getLastPostAttribute()
{
    return $this->posts->last(); //update to not use builder instance
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...