Представьте себе сценарий в стиле Twitter, где один пользователь может следовать за другим. Затем пользователь может видеть сообщения (или твиты), которые сделали пользователи, за которыми он / она следит.
Пример структуры базы данных:
users (id, username, created_at, updated_at)
posts (id, user_id, body, created_at, updated_at)
follows (id, follower_id, followed_id, created_at, updated_at)
Модель пользователя
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
protected $table = 'users';
/* A user can follow another user */
public function followers()
{
return $this->belongsToMany('User', 'follows', 'follower_id', 'followed_id')->withTimestamps();
}
// ...
}
Теперь мой первоначальный подход с использованием Eloquent должен был сделать что-то вроде:
// Within the User model
public function getFeed()
{
// Ids of all follows
$ids = $this->follows()->lists('followed_id');
// Append this user's id
$ids[] = $this->attributes['id'];
// Grab up to 20 posts by people with these ids, ordered in descending order by date (Eager loading the user object associated with each post)
return Post::whereIn('user_id', $ids)->with('user')->latest()->take(20)->get();
}
Что приведет к следующим основным запросам:
select `followed_id` from `users` inner join `follows` on `users`.`id` = `follows`.`followed_id` where `follows`.`follower_id` = ?
select * from `posts` where `user_id` in (?, ?) order by `created_at` desc limit 20
select * from `users` where `users`.`id` in (?, ?)
В этом случае у меня в таблице только две записи пользователей, которые следуют друг за другом. Что бы произошло, если бы пользователь следил за 1 тысячей, 1 миллионом, 10 миллионами человек? Второй запрос станет очень длинным, возможно, слишком длинным? Возможно, такой подход вызовет другие проблемы.
Мой естественный подход к этой проблеме в SQL должен был бы сделать один запрос, что-то вроде:
SELECT p.body, p.created_at, u.username FROM follows AS f
LEFT JOIN posts AS p ON f.followed_id = p.user_id
LEFT JOIN users AS u ON p.user_id = u.id
WHERE f.follower_id = 1
ORDER BY p.created_at DESC
LIMIT 20
Подходит ли подход, который я выбрал, используя eloquent, и сможет ли он справиться (не зная количества записей пользователя / подписки, которые могут быть в будущем)? Если нет, есть ли другой подход, использующий eloquent, который был бы лучше? Было бы лучше сделать все в одном запросе SQL, как я сделал выше? Любые другие мысли / предложения приветствуются.
Мне нравится использовать Laravel с Eloquent, но я обеспокоен тем, что способ выполнения внутренних запросов может не всегда оказаться лучшим подходом. Это довольно умно, но я не ожидаю, что он сможет сделать все наилучшим образом.
Задача ещё не решена.
Других решений пока нет …