超过100万用户的laravel记分牌

8qgya5xd  于 2021-06-17  发布在  Mysql
关注(0)|答案(1)|浏览(274)

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

任何优化我应该使得到的结果更快?谢谢。

c3frrgcw

c3frrgcw1#

你一打电话 get() , all() , find() 或者 first() 在查询生成器上,您将要求雄辩的引擎执行查询并返回结果。所以在您的例子中,所有的排序和分组都是在内存中执行的,这会带来非常糟糕的性能。
您可以做的是改进您的查询:

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() .

相关问题