【问题标题】:Laravel model belongs to relationship loading issueLaravel 模型属于关系加载问题
【发布时间】:2019-03-13 14:40:26
【问题描述】:

我有两个模型,Box 和 BoxLocations。 BoxBoxLocations 具有 hasMany 关系,BoxLocationsBox 具有 belongsTo 关系。

BoxLocations 还具有一个附加到模型的属性,该属性需要来自 Box 关系的单条信息。

我注意到在调用Box::with(['BoxLocations']->)all(); 时,我看到BoxLocations 模型正在重新加载Box 关系。每个BoxLocation 都会发生这种情况(50 次奇数)

laravel 是否不会跟踪 Box 已经从初始 Box::with(['BoxLocations']->)all(); 请求中加载,然后将其传递给 BelongsTo 关系?

我正在尝试优化 Web 系统,当加载所采用的属性时(令人讨厌的是,每次加载时都需要它)它会导致 50 次对已加载的同一个 Box 模型的数据库的奇数命中。

如果 laravel 不这样做 - 有没有更好的方法来实现上述目标?

【问题讨论】:

    标签: laravel laravel-5.5


    【解决方案1】:

    当你使用 with() 方法时,Laravel 使用 eager loading

    当访问 Eloquent 关系作为属性时,关系数据是“延迟加载”的。这意味着在您第一次访问该属性之前,不会实际加载关系数据。但是,Eloquent 可以在查询父模型时“预先加载”关系。急切加载缓解了 N + 1 查询问题。

    如果你这样做:

    $boxes = Box::with('BoxLocations')->get();
    

    它已经加载了关系,但是假设你这样做:

    $boxes = Box::all();
    
    foreach($boxes as $box)
    {
      echo box->boxlocation->name;
    }
    

    如果您有 50 个框,则此循环将运行 51 个查询。

    但是当您使用with 方法并急切加载关系时,此循环将只运行 2 个查询。

    您也可以使用Lazy Eager Loading 并决定何时加载关系

    【讨论】:

    • 我已将此答案标记为正确;但是我发现 laravel 仍然通过这种方法执行了比我需要的更多的查询。我发现编写一个数据库查询以在一次数据库调用中获取我想要的字段比让 laravel 关系多次访问数据库要好得多
    • 谢谢,你能告诉我它使用关系执行了多少个查询吗?这可能是一个错误,我们可以报告它。另外,如果您显示您提出的查询,我将不胜感激
    • 我现在不记得代码了,但基本上我有一个制造商表,里面有“Apple”,还有一个设备表,里面有很多苹果产品。在执行Devices::with('manufacturers')->get() 时,您会得到每个设备制造商的单个查询。我认为它应该让制造商为第一个,然后为其余的缓存它。但是,这是在旧版 laravel 5.5 代码中。所以现在可能不是问题。
    猜你喜欢
    • 1970-01-01
    • 2020-08-09
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-29
    • 2021-07-19
    • 2017-07-26
    相关资源
    最近更新 更多