为什么 Laravel 不自动优化模型查询?

Why Laravel does not optimize model queries automatically?

直到今天,我一直依赖 Laravel 关系,但自从我打开 mysql 日志后,我感到非常失望。

当我执行代码时

Company::with(['users', 'machines'])->get()

mysql.log 看起来是这样

select * from `company` where `company`.`id` = '48' limit 1
select * from `user` where `user`.`company_id` in ('48')
select * from `machine` where `machine`.`company_id` in ('48')

为什么 Laravel 不使用连接进行预取?此外,是否有任何方法可以提高性能并仍然使用 Laravel 模型?

我知道 Doctrine ORM 预加载通过使用连接非常好。


感谢您的帮助。

如果你真的想使用联接而不是 Eloquent 计算查询,我想你可以使用流畅的查询构建器(通过数据库外观 Laravel 附带)并坚持将该代码放入模型的方法中,以保持一切良好和 SRP。

例如:

class Company extends Model {
    public function sqlWithJoin() {
        $users = DB::table('company')
        ->leftJoin('user', 'company.id', '=', 'user.company_id')
        ->get();

        return $users;
    }
}

这将为您生成正确的连接查询。

至于为什么要这样做,您必须对这两个选项进行基准测试,看看哪个选项能为您的特定数据提供最佳性能。我不会一概而论,一个选项总是比另一个选项具有 better/worse 性能。

如评论中所述,我不确定为什么这是首选方法的性能方面,但从可用性来看,能够访问模型的关系,因为它是独立的 属性 比与 join 一起工作,尤其是在 many-to-one 关系的情况下。

让我们使用 ->with()->leftJoin() 方法比较上面的例子。

当使用 ->with() 时,每个关系都定义为 Company 的 属性,通过 $company->users 访问。 运行 一个 foreach() 循环这个 属性 foreach($company->users AS $user) 并输出信息,例如 usernameemail 等,这很容易。此外,如果Company 没有 users,您不必担心显示空值(对于使用 . 符号的链接模型尤其重要,例如 users.user_details)。

现在,查看 leftJoin()。如果您尝试在每个模型及其子模型上链接多个 leftJoins(),您很可能得不到预期的结果。本质上,leftJoin() 处理 NULL 记录的能力不如单个查询。

接下来,要输出公司用户的列表,您必须 运行 一个循环,例如:

foreach($company AS $row){
    echo $row->username;
    echo $row->email;
    // etc etc
}

这会产生问题,因为 Eloquent 根本无法很好地处理重复的属性。例如,如果公司和用户都有一个 email 字段,那么实际显示的是任何人的猜测。除非您执行 selectRaw("companies.email AS email, users.email AS user_email)",否则只会返回一个 email 属性。这也适用于像 id 这样的列,其中将使用 leftJoin() 获取多个列,但实际上只能访问一个。

长话短说,leftJoin() 在尝试连接多个表时可能会出现很多问题,可能会出现重复信息、空信息等。而 运行 的性能使用 ->with() 方法进行多个查询可能不是最好的,它可以更轻松地用于检索和显示信息。