如何在laravel中处理大量数据而不出现超时错误?

问题描述 投票:0回答:1

我有一个与 GameLog 模型相关的 User 模型,User 有很多 GameLog 数据。现在我想为 vip 程序添加一个与用户相关的功能。在游戏日志中,我有数百万与用户相关的数据 当我添加 VIP 程序时,它将创建一种一对一的关系,当游戏日志中处理所有数据时,积分将增加到 VIP 程序,并且级别将根据积分进行更改 但是我怎样才能做到一次来处理现有数据。

public function handle()
    {
        $this->info('Processing game log...');

        User::query()
            ->with('game_logs')
            ->player()
            ->select('id')
            ->chunk(500, function ($users) {
                $users->each(function ($user) {

                    VipProgram::query()
                        ->firstOrCreate([
                            'user_id' => $user->id
                        ]);

                    $point = 0;
                    $user->game_logs()
                        ->where('is_processed', false)
                        ->chunk(1000, function ($gameLogs) use (&$point) {
                            $gameLogs->each(function ($gameLog) use (&$point) {
                                $point += $gameLog->bet_amount;
                                $gameLog->is_processed = true;
                                $gameLog->save();
                            });
                        });


                    $com_points = floor($point / 60);
                    $user->vip_program->awardPoint($com_points);
                });
            });

        $this->info('Game Log processed successfully!');
    }

我已经创建了这个,但它在 8 秒内处理了 100 万个数据,但是如果数据是 3000 万且用户是 60k 该怎么办 我怎样才能做到这一点 记住一件事,如果通过命令,我想运行一次命令 否则,任何其他方法都可以实现这一点,而且我需要在我们启动该功能时完成此操作,并且那天因为用户仍在玩并且数据正在存储

laravel eloquent job-scheduling
1个回答
0
投票

在处理大型数据集时,特别是当您只想执行一次操作时,优化代码的性能至关重要。以下是一些提高代码效率的建议:

数据库索引: 确保数据库表已正确建立索引,尤其是在 where 子句中使用的外键和字段上。索引可以显着加快数据检索速度。

使用Eloquent的更新方法: 您可以使用 update 方法一次更新多条记录,而不是加载每个游戏日志并单独更新。这减少了执行的查询数量。

利用数据库聚合: 您可以在查询中使用 SUM 等数据库聚合函数来直接在数据库中计算总积分,而不是在 PHP 中获取所有游戏日志并求和 bet_amount。

以下是包含这些建议的示例:

public function handle()
{
$this->info('Processing game log...');

User::query()
    ->with('game_logs')
    ->player()
    ->select('id')
    ->chunk(500, function ($users) {
        foreach ($users as $user) {
            VipProgram::query()
                ->firstOrCreate(['user_id' => $user->id]);

            $totalPoints = $user->game_logs()
                ->where('is_processed', false)
                ->sum('bet_amount');

            // Update game logs in bulk
            $user->game_logs()
                ->where('is_processed', false)
                ->update(['is_processed' => true]);

            // Calculate and award points
            $compPoints = floor($totalPoints / 60);
            $user->vip_program->awardPoint($compPoints);
        }
    });

$this->info('Game Log processed successfully!');
}

此代码使用数据库聚合来计算总积分,然后更新游戏日志并批量奖励积分,这应该会提高性能。

© www.soinside.com 2019 - 2024. All rights reserved.