Laravel计分板超过100万用户

时间:2018-11-22 18:53:07

标签: php mysql laravel apache laravel-5

我正在使用最大的应用程序(超过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;
        });

任何优化都应该使结果更快吗?谢谢。

1 个答案:

答案 0 :(得分:2)

在查询构建器上调用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()使用分页。