<?php
class Cat extends Eloquent {
public function user() {
return $this->belongsTo('User');
}
}
class User extends Eloquent {
public function cats() {
return $this->hasMany('Cat');
}
}
:
$cats = Cat::with('user')->get();
执行2次查询:
select * from `cats`
select * from `users` where `users`.`id` in ('1', '2', 'x')
为什么它不能做:
select * from cats inner join users on cats.user_id = users.id
对于那些说表中有两个id列的人,可以很容易地使用别名来避免:
select
c.id as cats__id,
c.name as cats__name,
c.user_id as cats__user_id,
b.id as users__id,
b.name as users__name
from cats c
inner join users b on b.id = c.user_id
有人指出Eloquent不知道模型中表的列,但我想他们可以提供一种在模型中定义它们的方法,这样它就可以使用别名并进行适当的连接,而不是额外的查询。
我的猜测是,这允许即时加载多个一对多关系。例如,我们还有一个dogs表:
class User extends Eloquent {
public function cats() {
return $this->hasMany('Cat');
}
public function dogs() {
return $this->hasMany('Dog');
}
}
现在我们想用User:
来加载它们$users = User::with('cats','dogs')->get();
没有连接可以将这些组合成单个查询。但是,对每个"with"元素单独执行查询是可行的:
select * from `users`
select * from `cats` where `user`.`id` in ('1', '2', 'x')
select * from `dogs` where `user`.`id` in ('1', '2', 'x')
因此,虽然这种方法可能在一些简单的情况下产生额外的查询,但它提供了渴望加载更复杂的数据的能力,在这些数据中,连接方法将失败。
这是我对为什么是这样的猜测。
我认为,当您想使用LIMIT和/或OFFSET时,连接查询方法有一个致命的缺点。
$users = User::with('cats')->get() -这将输出以下2个查询:
select * from `users`
select * from `cats` where `user`.`id` in ('1', '2', 'x')
而不是一个查询
select * from users inner join cats on cats.user_id = users.id
但是我们说,我们需要为这个记录集分页
User::with('cats')->paginate(10) -这将有限制地输出以下2个查询。
select * from `users` limit 10
select * from `cats` where `user`.`id` in ('1', '2', 'x')
加一个join,就像
select * from users inner join cats on cats.user_id = users.id limit 10
它将获取10条记录,但它并不意味着10个用户,因为每个用户可以有多个猫。
我认为另一个原因是关系数据库和NOSQL数据库之间的关系可以很容易地通过分离查询方法实现
和前面的答案一样,id是不明确的,你必须在每个语句前加上表名,这是不需要的。
另一方面,JOIN比EXISTS开销大,而EXISTS速度快,因为它不命令RDBMS获取任何数据,只检查相关行是否存在。EXISTS用于返回一个布尔值,JOIN返回另一个完整的表。
出于可伸缩性的目的,如果遵循分片架构,将不得不删除JOIN。这是pinterest在扩展期间的实践。http://hilicalability.com/blog/2013/4/15/scaling-pinterest-from-0-to-10s-of-billions-of-page-views-a.html
cats
和users
可能都有一个名为id
的列,使您建议的查询模棱两可。Laravel的急切加载使用了一个额外的查询,但是避免了这个潜在的错误。