Табло Laravel более 1 миллиона пользователей - PullRequest
0 голосов
/ 22 ноября 2018

Я работаю в самом большом приложении (более 1 миллиона пользователей) и пытаюсь получить рейтинг каждого пользователя в разделе табло, но у меня возникла такая проблема: результат очень очень медленный

Это архитектура моей базы данных:

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 голосов
/ 22 ноября 2018

Как только вы вызовете 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().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...