想象一下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 (?, ?)
在这种情况下,我的表中只有2个用户记录,彼此跟随。如果用户跟踪了1千,1百万,1千万人会怎么样?第二个查询会变得很长,也许太长了?也许这种方法会引起其他问题。
我在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
我采用的方法是否恰当,并且能否应对(不知道将来可能会有用户/跟踪记录的数量)?如果没有,是否有另一种使用雄辩的方法会更好?如上所述,在一个SQL查询中执行所有操作会更好吗?任何其他想法/建议表示赞赏。
我喜欢将Laravel与Eloquent一起使用,但我担心它在底层执行查询的方式可能并不总是被证明是最好的方法。它非常聪明,但我不希望它能够以最好的方式做所有事情。