我正在使用最大的应用程序(超过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;
});
任何优化都应该使结果更快吗?谢谢。
答案 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()
使用分页。