【问题标题】:Laravel Eloquent - Is it inefficientLaravel Eloquent - 效率低吗
【发布时间】:2015-08-16 20:29:16
【问题描述】:

我正在考虑使用 Laravel 开发一个新网站。我正在阅读http://vegibit.com/laravel-eloquent-orm-tutorial/ 上的教程,关于使用 Eloquent 连接表和检索数据。在最后一个示例中,他们实际上是在尝试进行连接,但 Eloquent 仍然在执行两个查询而不是一个。是 Eloquent 效率低下还是这只是一个糟糕的例子?似乎这可以简单地通过一个左连接查询来完成。任何人都可以对此提供一些见解吗?有没有更好的方法来执行这个查询?具体例子是:

Route::get('/', function()
{
    $paintings = Painting::with('painter')->get();

    foreach($paintings as $painting){
        echo $painting->painter->username;
        echo ' painted the ';
        echo $painting->title;
        echo '<br>';
    }

});

导致以下查询:

string ‘select * from paintings‘ (length=25)
string ‘select * from painters where painters.id in (?, ?, ?)’ (length=59)
Leonardo Da Vinci painted the Mona Lisa
Leonardo Da Vinci painted the Last Supper
Vincent Van Gogh painted the The Starry Night
Vincent Van Gogh painted the The Potato Eaters
Rembrandt painted the The Night Watch
Rembrandt painted the The Storm on the Sea of Galilee

【问题讨论】:

  • 我对这个主题没有权威,但正如我所见,雄辩总是比直接与数据库交谈要慢,因为创建查询会产生开销,然后将所有结果绑定到您正在使用的任何模型的实例。无论如何,这不会是无法承受的开销,但它会以某种形式存在。您对新项目的预期负载是什么?
  • 您始终可以创建视图并拥有只读的 eloquent 模型,以便于访问数据库。我对此的尝试是 eloquent 不会执行连接,因为每个模型都是独立的,您可以更新每个模型,而不管它们之间的任何类型的关系,这可能是它选择执行两个查询的原因更容易映射到对象。再说一次,我可能是错的,但事实是——如果你想要一个连接、一个查询和 eloquent 的所有好处——你可以实现它。
  • 我还没有做出任何最终决定。在以前的项目中,我总是手动编写查询,所以我并不反对。一位朋友最近在吹嘘 Eloquent 是多么简单,但当我可以快速启动查询时,我并没有看到真正的优势。我们预计会产生一些复杂查询的负载,因此效率很重要。
  • 使用 Eloquent 会更快。并不是查询很难构建,Eloquent 为您做的就是让您能够快速地对一组表执行 crud。我说的是经验,因为办公室里的人试图说服我几个星期,Eloquent 和 Doctrine 击败了手动查询。在我放弃之后,我可以保证使用 ORM 绝对可以帮助您更快地开发,而且最好的部分是您可以更轻松地进行测试。

标签: php mysql laravel eloquent


【解决方案1】:

如果您想要在单个查询中获取所有数据以使用连接,那么您必须将其指定为:

Painting::join('Painter as p', 'p.IdPainter', '=', 'Painting.IdPainting')->get()

如果你需要一些条件,那么:

Painting::join('Painter as p', 'p.IdPainter', '=', 'Painting.IdPainting')->where('cond1', '=', 'value')->get();

个人Eloquent效率低下,在这方面我更喜欢Doctrine。

【讨论】:

  • 有任何事实支持您关于 Eloquent 与 Doctrine 相比效率低下的说法,还是我们应该相信您的话?我喜欢相信我可以复制并亲眼看到的东西。你的回答在这方面没有帮助。
  • 如果你觉得 Doctrine 高效而 eloquent 低效,那你就错了。
  • 我亲自对我说,Eloquent 不符合我的期望。这篇评论来自经验,我当然很容易提出质疑,为什么我不争论,但是这不支持数据库中更复杂的结构,例如复合键,至少在本机上。
【解决方案2】:

Eloquent 对于快速构建东西非常有用,并且还具有查询缓存,它非常易于使用,但是对于需要随时间扩展的大型项目,它可能并不理想,我的方法是使用 Repository 模式和合约,这样我仍然可以使用 Eloquent 的强大功能,并且有一个系统可以让我在需要时轻松更改实现。

【讨论】:

    【解决方案3】:

    对您的问题的简单回答:不。这不是低效的。

    以 Jorge 描述的方式使用 Eloquent 确实违背了它作为 ORM 的目的。

    虽然您可以按照给出的示例编写连接,但 ORM 的设计确实没有考虑到这一点。

    您给出的示例不是n+1 query(循环中的每个项目都有一个额外的查询运行 - 最糟糕的查询类型)。

    使用您的输出报告的两个查询并不是很大的开销,我认为您可以在生产中使用它。您对 Eloquent 的“with”eager loading 的使用正是您在这种情况下应该使用的。

    n+1 查询的示例(您要避免)如下:

    foreach (Book::all() as $book)
    {
        echo $book->author->name;
    }
    

    如果Book::all() 返回了 20 本书,那么循环将总共执行 21 次查询。 1 获取所有书籍,每次迭代 $book 1 获取作者姓名。

    将 Eloquent 与预加载结合使用,并结合缓存将足以最大限度地减少任何性能问题。

    【讨论】: