【问题标题】:Laravel scoreboard of more than 1 million users超过 100 万用户的 Laravel 记分牌
【发布时间】:2018-11-22 18:53:06
【问题描述】:

我在一个最大的应用程序中工作(超过 100 万用户),我尝试在记分牌部分获取每个用户的排名,但遇到了这个问题:结果非常非常慢

这是我的数据库的架构:

Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            ...
});

Schema::create('topics', function (Blueprint $table) {
            $table->increments('id');
            ...
});

主题表超过 20 行


    Schema::create('user_scores', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('user_id')->unsigned();
        $table->integer('topic_id')->unsigned();

        $table->unique(['user_id', 'topic_id']);

        $table->float('timer');
        $table->integer('score');
     });

为用户排名的查询

        User::where('type',0)->get()->each(function ($user) {
            $user->topics= $user->scores->sum('score');
            $user->timing= $user->scores->sum('timer');
        })->sort(function ($a, $b){
          return  ($b->topics - $a->topics) == 0  
            ? ($a->timing - $b->timing) 
            : ($b->topics - $a->topics);
        })->values()->each(function($user, $key){
                $user->rank = $key +1;
        });

我应该进行任何优化以更快地获得结果吗?谢谢。

【问题讨论】:

  • 你不能期望每个人都猜测你正在执行什么查询。请举一些例子,否则任何建议都只是一个更好的猜测......
  • 你在PHP数组中排序,这就是为什么速度...尝试对数据库中的行进行排序
  • @Alex 请举个例子

标签: php mysql laravel apache laravel-5


【解决方案1】:

只要您在查询构建器上调用 get()all()find()first(),您就会要求 Eloquent 引擎执行查询并返回结果。所以在你的情况下,所有的排序和分组都是在内存中执行的,这带来了非常糟糕的性能。

您可以做的是改进您的查询:

User::query()
    ->where('type', 0)
    ->withCount('scores as topics')
    ->withCount(['scores as timing' => function ($query) {
        $query->selectRaw('SUM(timer)'); // might look weird, but works...
    }])
    ->orderBy('topics', 'desc')
    ->orderBy('timing', 'desc')
    ->get()

对于行号(或排名,或者您想怎么称呼它),您可能需要搜索现有的问题和答案。老实说,对于这个答案来说,回答这个问题也太过分了。显然你不应该使用你的方法,因为它也会计算内存中的行号。

但显然,您对查询结果所做的工作也很重要。您是否向用户显示一百万行?如果是这样,瓶颈肯定是浏览器。您可能需要考虑使用paginate() 而不是get() 的分页。

【讨论】:

  • 'withCount' 仅返回行数(始终为 1)。我不显示所有结果我只得到前 3 名,以及连接用户之前和之后(user-1、user、user+1)
  • withCount('scores') 将返回score 表中关联的行数。您可以使用toSql() 而不是get() 打印查询以自己查看。
  • 我需要按总和的值排序,而不是按行数
  • 然后只需切换 orderBy() 语句。
猜你喜欢
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
  • 2019-11-23
  • 2016-01-24
  • 2023-03-09
  • 1970-01-01
  • 2014-04-22
  • 2020-10-31
相关资源
最近更新 更多