【问题标题】:Optimizing Queries - Eager loading takes too much memory优化查询 - 急切加载占用过多内存
【发布时间】:2014-12-09 16:27:07
【问题描述】:

我有以下表格:

  • 用户(大约 1.000 行)
  • 粉丝(大约 100.000 行)- 一个用户有很多粉丝,一个粉丝属于一个用户
  • 赞(大约 100.000 行 - 一个用户有很多赞,一个赞属于一个用户

现在我想要一张桌子

  • 用户名
  • 粉丝数
  • 点赞数

这是一个大表,我使用 jQuery DataTable 将它与分页一起使用,但这里是关于服务器端的。

我已经建立了我所有的关系并输出了表格:

$users = User::get();

foreach ($users as $user) {
echo $user->name;
echo $user->fans()->count();
echo $user->likes()->count();
}

这是很多查询,我想优化。我的第一次尝试是使用 Eager Loading。

$users = User::with('fans', 'likes')->get();

但这似乎对服务器内存非常不利。在我的本地环境中,我有 16 MB 的内存大小用于 php 脚本。而且它总是试图分配更多。

这正常吗? 简单地为脚本提供更多内存的最佳解决方案是什么? 我还能如何优化我的查询?

【问题讨论】:

  • 16mb 用于 php 脚本?这根本不是很多。
  • 是的,the default 是 128 MB。
  • 您是对查询进行分页(使用限制和偏移)还是只是将其全部拉出然后在内存中排序?

标签: php mysql laravel laravel-4 eloquent


【解决方案1】:

如果您只想计算记录数,那么获取所有记录只是为了计算它们是没有意义的,现在您将获得 201000 行。您应该添加:

public function fansCountRelation()
{
    return $this->hasOne('Fan')->selectRaw('user_id, count(*) as count')
        ->groupBy('user_id');
}


public function likesCountRelation()
{
    return $this->hasOne('Like')->selectRaw('user_id, count(*) as count')
        ->groupBy('user_id');
}

public function getLikesCountAttribute()
{

    return $this->likesCountRelation ?
        $this->likesCountRelation->count : 0;
}

public function getFansCountAttribute()
{

    return $this->fansCountRelation ?
        $this->fansCountRelation->count : 0;
}

到您的 User 模型,现在您将只获得 1000 个用户行 + 粉丝和喜欢的聚合数据。

现在你可以使用:

$users = User::with('fansCountRelation', 'likesCountRelation')->get();
foreach ($users as $user) {
    echo $user->name;
    echo $user->likes_count;
    echo $user->fans_count;
}

但是,如果您真的需要它,您应该重新考虑。正常使用的 1000 行太多了。如果您将它用于导出目的,那很好,但如果您只在管理面板中显示它,您应该为此使用分页。

如果您需要很多时间,您应该确保您的 fanslikes 表的索引为 user_id 列。它应该会大大加快您的查询速度。

【讨论】:

  • 感谢这项工作。不,我的记忆力不够,但速度甚至比没有 Eager Loading 的情况下还要糟糕。没有它需要2.5秒。现在使用 Eader Loading 需要 3.6 秒。
  • @almo 你在user_id 列上有fanslikes 表的索引吗?如果不是,您应该创建它们。
  • @Nabialek,是的,我有索引。
  • @almo 然后您应该检查您的 SQL 查询 stackoverflow.com/questions/26232815/… 并使用 EXPLAIN 在 phpmyadmin 中检查它们以检查发生了什么。还要确保您使用with,正如我在回答中显示的那样
  • @almo 如果您不使用with 并且不使用likes_count 和fans_count 并且如果单独检查这两个关系的时间很短,您也可以检查时间,因为问题可能只针对其中之一或者是数据库服务器问题
猜你喜欢
  • 1970-01-01
  • 2019-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多