我有一个与 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 该怎么办 我怎样才能做到这一点 记住一件事,如果通过命令,我想运行一次命令 否则,任何其他方法都可以实现这一点,而且我需要在我们启动该功能时完成此操作,并且那天因为用户仍在玩并且数据正在存储
在处理大型数据集时,特别是当您只想执行一次操作时,优化代码的性能至关重要。以下是一些提高代码效率的建议:
数据库索引: 确保数据库表已正确建立索引,尤其是在 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!');
}
此代码使用数据库聚合来计算总积分,然后更新游戏日志并批量奖励积分,这应该会提高性能。