【问题标题】:High CPU usage with Laravel Eloquent filteringLaravel Eloquent 过滤的高 CPU 使用率
【发布时间】:2023-03-10 21:50:01
【问题描述】:

我需要挑选出用户当前所在的所有团队,这是我的 Eloquent 代码:

$teams = Team::orderBy('created_at', 'desc')->get()->filter(function($team) use ($user)
{
    return $team->inTeam($user);
});

团队的花名册是用户 ID 数组,以字符串形式存储在数据库中。

这是 inTeam 函数:

public function inTeam($user)
{
    $id = $user->id;
    $players = $this->getPlayers();

    foreach ($players as $p)
    {
        if (is_null($p)) continue;
        if ($p == $id) return true;
    }
    return false;
}

每当加载包含此代码的页面时,我的服务器 CPU 使用率在 apache2 上飙升至约 60%+,在 mysqld 上飙升至约 30%,我无法弄清楚原因。在 Team 模型上使用 filter() 是我发现的最简洁的方式来做我需要的事情,它只会导致问题,甚至在足够多的用户加载页面时使网站停止。

有什么方法可以优化过滤,或者我需要重组我的数据库保存名册信息的方式吗?

编辑:我更新了我的代码以使用 FIND_IN_SET 并设法将 CPU 时间从 8 秒缩短到 5 秒。然而,仍然不理想。

$teams = Team::orderBy('id', 'desc')->whereRaw("FIND_IN_SET(" . $user->id . ", players_list)")->get();

我不知道如何为此规范化我的数据库,因为 players_list 列的长度根据 EventTeam 绑定的不同,因此以逗号分隔的字符串。

【问题讨论】:

  • 如您所见,这很糟糕。规范化你的数据库并在那里做。现在,使用find_in_set - dev.mysql.com/doc/refman/5.5/en/… 它将使用1,5,10 字符串完成这项工作。也读这个stackoverflow.com/questions/27898953/…
  • 我已经更新了我的帖子,以反映切换到FIND_IN_SET 这有点帮助。我不知道如何为此规范化我的数据库,因为EventTeam 绑定的players_list 列的长度不同,因此用逗号分隔字符串。
  • 你正在做的列 FIND_IN_SET 是索引吗?
  • @Kairu 只需为 teamsplayers 之间的 mm 关系创建一个数据透视表 - 这是您以正常形式处理多对多关系的方式,而不是逗号分隔的 id。跨度>

标签: php eloquent filtering cpu-usage


【解决方案1】:

过滤意味着您从 MySQL 中检索所有数据,然后搜索包含结果的大数组。

对于大型数据集,我建议使用 SQL 条件而不是 php 端过滤。

如果您想要一个有效的 sn-p,请发布有关您的数据库的更多信息。否则,请检查文档中的 where / whereIn 等:http://laravel.com/docs/5.0/eloquent#basic-usage

【讨论】:

  • 我会使用 SQL 条件检查,但是花名册列表保存为用户 ID 的字符串/数组,如下所示:421,918,48,如果我要检查用户 ID“21”是否在该名册,由于“421”,它将返回 true。
  • 正如 Jarek Tkaczyk 之前所说。将 ID 存储在字符串中对于查询速度来说效率不高。它需要数据库引擎解析字符串,搜索字符串等......也许你应该将字符串拆分成一个数据透视表。
猜你喜欢
  • 2018-03-19
  • 2016-07-14
  • 2017-10-14
  • 2013-05-29
  • 2023-03-27
  • 2020-08-26
  • 2019-02-22
  • 1970-01-01
  • 2014-08-26
相关资源
最近更新 更多