问题描述
我正在尝试将我们的数据库从 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,但同样的事情发生了。 update 函数总是返回 true,所以我必须假设 Laravel 认为每一行在执行时都会更新。
解决方法
Laravel documentation on chunking 中有一个重大警告:
在块回调中更新或删除记录时,对主键或外键的任何更改都可能影响块查询。这可能会导致记录未包含在分块结果中。
您需要找到另一种方法来批量更新您的密钥。我使用了以下问题的答案中描述的技术: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]);
}
}