Php 为什么可以';t Laravel/雄辩地使用JOIN进行快速加载?

Php 为什么可以';t Laravel/雄辩地使用JOIN进行快速加载?,php,join,laravel-4,eloquent,eager-loading,Php,Join,Laravel 4,Eloquent,Eager Loading,执行2个查询: $cats = Cat::with('user')->get(); 为什么它不能做到: select * from `cats` select * from `users` where `users`.`id` in ('1', '2', 'x') 对于那些表示表中有两个id列的人,可以使用别名轻松避免: select * from cats inner join users on cats.user_id = users.id 更新 有人指出,Eloquent不知道

执行2个查询:

$cats = Cat::with('user')->get();
为什么它不能做到:

select * from `cats`
select * from `users` where `users`.`id` in ('1', '2', 'x')
对于那些表示表中有两个id列的人,可以使用别名轻松避免:

select * from cats inner join users on cats.user_id = users.id
更新


有人指出,Eloquent不知道模型中表的列,但我想他们可以提供一种在模型中定义它们的方法,这样它就可以使用别名并进行适当的连接,而不是额外的查询。

cats
用户
可能都有一个名为
id
的列,使您的建议查询模棱两可。Laravel的急切加载使用了一个额外的查询,但避免了这个潜在的问题。

我猜这允许急切加载多个一对多关系。比如说,我们还有一张狗桌:

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
现在,我们希望通过用户加载它们:

class User extends Eloquent {

    public function cats() {
        return $this->hasMany('Cat');
    }

    public function dogs() {
        return $this->hasMany('Dog');
    }
}
没有连接可以将这些合并到单个查询中。但是,对每个“with”元素执行单独的查询确实有效:

$users = User::with('cats','dogs')->get();
因此,虽然这种方法在一些简单的情况下可能会产生额外的查询,但它提供了在join方法失败时加载更复杂数据的能力


这是我对为什么会这样的猜测

我认为,当您想使用LIMIT和/或OFFSET时,连接查询方法有一个致命的缺点

$users=User::with('cats')->get()-这将输出以下两个查询

select * from `users`
select * from `cats` where `user`.`id` in ('1', '2', 'x')
select * from `dogs` where `user`.`id` in ('1', '2', 'x') 
而且它不是一个单一的查询

select * from `users`
select * from `cats` where `user`.`id` in ('1', '2', 'x')
但我们要说的是,我们需要对这组记录进行分页

User::with('cats')->paginate(10)-这将输出以下2个带限制的查询

select * from users inner join cats on cats.user_id = users.id
加入一个join,它会像

select * from `users` limit 10
select * from `cats` where `user`.`id` in ('1', '2', 'x')
它将获取10条记录,但并不意味着10个用户,因为每个用户可以有多个CAT

我认为另一个原因是,使用分离查询方法可以很容易地实现关系数据库和NOSQL数据库之间的关系

和前面的答案一样,id是不明确的,您必须在每个语句前面加上不需要的表名

另一方面,JOIN比EXISTS昂贵,EXISTS更快,因为它不要求RDBMS获取任何数据,只需检查相关行是否存在。 EXISTS用于返回布尔值,JOIN返回整个其他表

出于可伸缩性目的,如果遵循分片体系结构,则必须删除连接。pinterest在缩放过程中进行了实践。

你说得对。这不是一种将表名附加到返回列的方法吗?像
cat.id
cat.name
user.id
,等等?在查询中处理别名(例如
cat.id as cat_uid
)是很简单的,我希望ORM能够从容应对。@IMSoP确切地说,我也希望如此。@IMSoP不同于某些ORM,Eloquent不知道表中有哪些列-大多数时候它都在执行
SELECT*
。它不知道要别名哪些列。@ceejayoz在上面看到我关于为每个联接返回一个额外的“分隔符”列的评论(这是我在调试中经常使用的技巧)。当然,构建一个使用联接的ORM是可能的,而不需要事先知道非键列。这要么是雄辩者的设计决定,要么只是他们不想修正的限制。@deczo Ahmmm。。。因为它是1个查询而不是2个查询?
Cat
上的
user\u id
不可为空,每个
Cat
都属于一个
用户
。。。那么为什么不
内部连接
?@deczo再说一次,如果ORM设计者想解决这个问题,这不是一个大问题。对象的定义可以很容易地区分“总是有”与“有时有”,或“肯定有”与“可能有”的检索,并适当地选择内部连接、左连接或右连接。我不知道雄辩,所以也许他们只是决定简单点。@deczo我不认为我在跟踪你。join子句的存在是有原因的,因此您不必进行额外的查询来匹配不同表中的行。如果你在谈论不同类型的连接,比如左,右,内。。。我想你可以根据模型中的关系来判断使用哪一个
belongsTo
意味着它始终属于,因此外键不能为空。他们可以添加另一个类似于
canBelongTo
的函数,它允许外键为null,因此它将使用left-join。不知道,只是说…ORM只是让生活更轻松的另一层。它的主要目的是对开发人员友好,我认为这一点非常简单。它有缺陷和局限性,有性能问题,代码中也有不一致之处,但另一方面,它真的很有说服力,非常适合简单的任务。然而,没有足够灵活的ORM来满足所有要求,这就是为什么你(我)不使用ORM来处理更复杂的工作。@emzero,我最近开始查看laravel,我面临着完全相同的问题,我不敢相信开发人员怎么会说额外的查询是可以的,join将完成工作的位置和/或选择*
为OK这适用于NM和1N关系,但不适用于11或N1。即使您只实现了这个2-仍然有很大的改进,特别是对于大型集合。(另外,1N也可以通过一个额外的查询来解决,而不管集合中的记录数是多少)对于
belongsTo
关系,这不适用,但对于belongsTo,雄辩可以使用join,而对于hasMany,
则可以使用另一个查询,没有任何连接可以将这些连接组合到一个查询中。
是的,它是左连接
select * from `users` limit 10
select * from `cats` where `user`.`id` in ('1', '2', 'x')
select * from users inner join cats on cats.user_id = users.id limit 10