在Eloquent查询中防止模型水合

时间:2018-03-08 16:49:53

标签: php mysql laravel performance eloquent

是否可以让雄辩的查询构建器返回StdClass而不是Model

例如,User::where('age', '>', 34)->get()会返回CollectionUser个模型。

DB::table('users')->where('age', '>', 34)->get()会返回CollectionStdClass个对象。快多了。

因此:

是否可以防止水合雄辩模型并将StdClass对象作为数据库查询构建器返回,但仍然可以利用雄辩查询构建器的有用性语法?

我不明白为什么这个问题被投票否决了。它的期望和措辞非常明确。人们应该将鼠标悬停在低投票图标上并看到建议“这个问题没有显示出任何研究成果;它不清楚且无益。”

Laravel社区坚信,如果你走出Eloquent,你就会过早地进行优化。这是不正确的,在有10,000多行保湿的情况下,数据库结果中的Eloquent模型极其缓慢。我们正在谈论秒,有时几十秒和沉重的记忆。

Laravelers然后会说“只做一个DB::query()更快”。是的......是的...它是我意识到的......虽然我在这个问题中提出问题......就在这里......上面......措辞简洁明了......我可以使用 Eloquent Query Builder 构建查询并返回StdClass对象,以便不会为数千个Eloquent模型带来所有开销。我已经听说Laravelers“为什么不用DB::query()呢?”因为我要求...我问我们是否可以使用 Eloquent语法,它比连接更容易,更易读....

我不在这里询问有关应用程序架构的建议。我们希望这样做有很多深层原因,例如匹配我们的ElasticSearch存储库的输出等......但我不应该深入了解原因 - 这是一个问答论坛。不是讨论或建议平台。

  • 脸掌

2 个答案:

答案 0 :(得分:4)

首先,这是一个非常好的问题。所有那些人都在那里讨厌,让OP休息一下!他是亲Laravel,这不是一个Eloquent sucks问题,真是太酷了。

在我看来,

  

保湿模型很少影响应用程序性能

那里有很多ORM,如果你看一下任何框架,这些问题就会不断涌现 - 但事实上,正如我已经意识到的那样,ORM几乎不会影响性能。

  

匪徒往往是查询本身而不是   ORM

让我举几个例子说明为什么Eloquent模型可能比DB facade查询慢?

<强> 1。模特活动:

如果您的模型中有model events(例如保存,创建等),它们有时会降低处理速度。不是说应该避免事件,你只需要小心何时何时不使用它们

<强> 2。加载关系:

无数次我看到人们使用Eloquent提供的appends列表加载关系,有时模型有5-10个关系。每次启动Eloquent查询时,这都是5-10个连接!如果将它与数据库外观查询进行比较,肯定会更快。但话说回来,谁是真正的罪魁祸首?不是ORM,它是查询(带有额外的连接!)

作为一个例子,不久有人问a question on this,他/她想知道为什么Eloquent查询比原始查询慢。看看吧!

第3。不了解触发Eloquent查询的内容

这是迄今为止人们认为ORM较慢的最重要原因。他们通常(并非总是)不明白触发查询的内容。

例如,假设您要更新products表并将产品#25的价格设置为250美元。

也许,您在控制器中写下以下内容:

$id = 25;
$product = Product::findOrFail($id);
$product->price = 250;
$product->save();

然后,你的同事说嘿,这太慢了。尝试使用DB facade。所以你写道:

$id = 25;
DB::table('products')->where('product_id', $id)->update(['price' => 250]);

繁荣!它更快。同样,罪魁祸首不是ORM。这是查询。上面的一个实际上是2个查询,findOrFail触发select *查询,save触发更新查询。

您可以而且应该使用Eloquent ORM将其写为单个查询,如下所示:

Product::where('product_id', 25)->update(['price' => 250]);

查询优化的一些优秀做法

  1. 让您的数据库完成大部分工作而不是PHP :例如。而不是迭代Eloquent集合,可能以数据库为您工作的方式构建数据库查询。

  2. 单个更新的批量更新:非常明显。避免在for循环中保存模型,yuk!

  3. 对于繁重的查询,请使用事务:数据库事务避免对每个插入重新编制索引。如果您确实需要在单个函数调用中调用数千个插入/更新查询,请将它们包装到事务中

  4. 最后但并非最不重要,如果有疑问,请检查您的查询:如果您曾经有过怀疑,或许ORM是真正的罪魁祸首 - 请再想一想!检查您的查询,尝试并优化它。

  5. 如果ORM正在减慢速度,请使用obervers或Laravel debugbar来比较有和没有ORM的查询。通常情况下,你会发现查询是不同的,区别不在于水合作用,而是实际的查询本身!

答案 1 :(得分:1)

是的,可以使用'getQuery'或'toBase'方法。例如:

User::where('age', '>', 34)->getQuery()->get();

User::where('age', '>', 34)->toBase()->get();