简体   繁体   English

为什么Laravel / Eloquent不能使用JOIN进行预先加载?

[英]Why can't Laravel/Eloquent use JOIN for Eager Loading?

<?php

class Cat extends Eloquent {

    public function user() {
        return $this->belongsTo('User');
    }
}

class User extends Eloquent {

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

Now: 现在:

$cats = Cat::with('user')->get();

Performs 2 queries: 执行2个查询:

select * from `cats`
select * from `users` where `users`.`id` in ('1', '2', 'x')

Why can't it just do: 为什么不能这样做:

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

For those saying that there are both id columns in the table, that could be easily avoided with aliases: 对于那些说表中有两个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

UPDATE UPDATE

Someone pointed out that Eloquent doens't know the columns of the tables from the models, but I guess they could provide a way to define them in the model so then it could use aliases and do a proper join instead of an extra query. 有人指出,Eloquent并不知道模型中表的列,但我猜他们可以提供一种在模型中定义它们的方法,这样它就可以使用别名并进行正确的连接而不是额外的查询。

My guess is that this allows for eager loading multiple one to many relationships. 我的猜测是,这允许急切加载多个一对多的关系。 Say, for instance, we also had a dogs table: 比如说,我们还有一张狗桌:

class User extends Eloquent {

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

    public function dogs() {
        return $this->hasMany('Dog');
    }
}

Now we want to eager load them both with the User: 现在我们想要用户急切加载它们:

$users = User::with('cats','dogs')->get();

There is no join that would work to combine these into a single query. 没有联接可以将这些组合成单个查询。 However, doing a seperate query for each "with" element does work: 但是,对每个“with”元素执行单独查询确实有效:

select * from `users`
select * from `cats` where `user`.`id` in ('1', '2', 'x')
select * from `dogs` where `user`.`id` in ('1', '2', 'x') 

So, while this methodology may produce an extra query in some simple circumstances, it provides the ability to eager load more complex data where the join method will fail. 因此,虽然这种方法可能会在某些简单的情况下产生额外的查询,但它提供了在连接方法失败时急切加载更复杂数据的能力。

This is my guess as to why it is this way. 这是我猜测为什么会这样。

cats and users likely both have a column named id , leaving your suggested query ambiguous. catsusers可能都有一个名为id的列,使您建议的查询不明确。 Laravel's eager loading uses an additional query, but avoids this potential mishap. Laravel的急切加载使用了额外的查询,但避免了这种潜在的不幸事件。

I think, join query approach has a fatal drawback when you want to use LIMIT and/or OFFSET. 我认为,当你想使用LIMIT和/或OFFSET时,连接查询方法有一个致命的缺点。

$users = User::with('cats')->get() - this will output the below 2 queries. $ users = User :: with('cats') - > get() - 这将输出以下2个查询。

select * from `users`
select * from `cats` where `user`.`id` in ('1', '2', 'x')

and its not one single query as 而且它不是一个单一的查询

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

but lets say, we need to paginate this record set. 但是让我们说,我们需要对这个记录集进行分页。

User::with('cats')->paginate(10) - this will output the below 2 queries with limit. User :: with('cats') - > paginate(10) - 这将输出以下2个限制查询。

select * from `users` limit 10
select * from `cats` where `user`.`id` in ('1', '2', 'x')

with a join, it will be like 加入,就像

select * from users inner join cats on cats.user_id = users.id limit 10

it will fetch 10 records but it does not mean 10 users, because every user can have multiple cats. 它将获取10条记录,但并不意味着10个用户,因为每个用户可以拥有多只猫。

Also another reason i think is, a relation between relational db and NOSQL db can be easily implemented with the separated query approach 我认为另一个原因是,关系数据库和NOSQL数据库之间的关系可以使用分离的查询方法轻松实现

Also as previous answer, id is ambiguous, and you would have to prefix every statement with the table name which is not desired. 同样如前面的回答,id是不明确的,你必须在每个语句前面加上不希望的表名。

On the other hand, JOIN is expensive than EXISTS and EXISTS is faster because it doesn't order RDBMS to fetch any data, just check whether relevant rows exist. 另一方面,JOIN比EXISTS昂贵,EXISTS更快,因为它不命令RDBMS获取任何数据,只检查相关行是否存在。 EXISTS is used to return a boolean value, JOIN returns a whole other table. EXISTS用于返回布尔值,JOIN返回整个其他表。

For Scalability purpose if following sharding architecture, will have to remove the JOIN's. 对于Scalability目的,如果遵循分片架构,则必须删除JOIN。 This was practiced by pinterest during the scaling. 这是在缩放期间通过pinterest实践的。 http://highscalability.com/blog/2013/4/15/scaling-pinterest-from-0-to-10s-of-billions-of-page-views-a.html http://highscalability.com/blog/2013/4/15/scaling-pinterest-from-0-to-10s-of-billions-of-page-views-a.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM