Laravel 更新分块结果跳过行

Laravel update chunked result skips rows

我正在尝试将我们的数据库从 ID 转换为 UUID。当我 运行 以下更新数据库的代码是跳过随机行。

AppUser::select('id')->orderBy('created_at')->chunk(1000, function ($appUsers) {
        foreach ($appUsers as $appUser) {
            $uuid = Str::orderedUuid();
            DB::table('files')->where('fileable_type', AppUserInfo::class)->where('fileable_id', $appUser->id)->update([
                'fileable_id' => $uuid
            ]);
            DB::table('app_users')->where('id', $appUser->id)->update(['id' => $uuid]);
        }
    });

我上次检查时,总计 236196 个中跳过了 ~290 个。

我试过使用 chunkById,但同样的事情发生了。 更新函数总是返回 true,所以我必须假设 Laravel 认为每一行在执行时都会更新。

Laravel documentation on chunking中有一个很大的警告:

When updating or deleting records inside the chunk callback, any changes to the primary key or foreign keys could affect the chunk query. This could potentially result in records not being included in the chunked results.

您需要找到另一种方法来批量更新您的密钥。我使用了这个问题的答案中描述的技术:How to chunk results from a custom query in Laravel 当我无法使用 chunk 方法所需的回调时,尽管在那种情况下它不适用于 update查询,只有一个select.

这就是我最后做的事情

$appUsers = AppUser::select('id')->get();
    $chunkSize = 1000;
    $numberOfChunks = ceil($appUsers->count() / $chunkSize);
    $chunks = $appUsers->split($numberOfChunks);
    
    foreach($chunks as $chunk) {
        foreach($chunk as $appUser) {
            $uuid = Str::orderedUuid();
            DB::table('files')->where('fileable_type', AppUserInfo::class)->where('fileable_id', $appUser->id)->update([
                'fileable_id' => $uuid
            ]);
            DB::table('app_users')->where('id', $appUser->id)->update(['id' => $uuid]);
        }
    }