Eug*_*per 1 php mysql laravel eloquent
我有一个计划的系统清理方法,该方法将遍历“存储”表中的所有文件,选择所需的文件类型(属性照片),然后遍历每个文件,以定义数据库中是否仍存在相应的清单。如果不是,请从数据库中删除记录并删除文件本身。
现在来解决这个问题。最初我不使用chunk(),只是使用Model :: all()来选择所有内容,并且一切都很好。但是此时,我在该存储表中有200000条记录,并且由于大量内存消耗,这些操作开始崩溃。因此,我决定使用chunk()。
因此,问题在于现在它可以正常工作了,但是,在某些随机时刻(过程中间的某个地方),代码执行就像操作已完成一样停止了,因此在任何地方都没有记录错误并且任务没有完全完成完成。
您能否提出造成这种奇怪行为的原因?
public function verifyPhotos() {
// Instantiating required models and putting them into a single array so they can be passed to a closure
$models = [];
$models['storage'] = App::make('Store');
$models['condo'] = App::make('Condo');
$models['commercial'] = App::make('Commercial');
$models['residential'] = App::make('Residential');
// Obtaining and processing all records from the storage chunk by chunk
$models['storage']->where('subject_type', '=', 'property_photo')->chunk(10000, function($files) use(&$models) {
// Going through each record in current chunk
foreach ($files as $photo) {
// If record's subject type is Condo
if ($photo->subject_name == 'CondoProperty') {
// Selecting Condo model to work with
$current_model = $models['condo'];
// If record's subject type is Commercial
} elseif ($photo->subject_name == 'CommercialProperty') {
// Selecting Commercial model to work with
$current_model = $models['commercial'];
// If record's subject type is Residential
} elseif($photo->subject_name == 'ResidentialProperty') {
// Selecting Residential model to work with
$current_model = $models['residential'];
}
// If linked listing doesn't exist anymore
if (!$current_model->where('ml_num', '=', $photo->owner_id)->first()) {
// Deleting a storage record and physical file
Storage::delete('/files/property/photos/'.$photo->file_name);
$models['storage']->unregisterFile($photo->id);
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
小智 5
chunk()在Eloquent中使用将为您的SQL查询添加一个限制和一个偏移量,并为每个块执行它。如果更改数据库中的数据以减少查询匹配的行,则由于偏移,您将在下一次执行中跳过匹配的行。
也就是说,如果你有9排,id = 1...9并subject_type = 'property_photo'和使用chunk(3, ...)所产生的疑问是:
select * from store where subject_type = 'property_photo' limit 3 offset 0;
select * from store where subject_type = 'property_photo' limit 3 offset 3;
select * from store where subject_type = 'property_photo' limit 3 offset 6;
select * from store where subject_type = 'property_photo' limit 3 offset 9;
Run Code Online (Sandbox Code Playgroud)
如果在subject_type = 'something'每行的每个块集内,这些行将不再匹配,并且下一个偏移量为3的查询将有效地跳过下一个3个匹配项。
也许可以像下面这样使用Collection :: each()闭包,尽管它仍然必须将整个结果集加载到集合中:
$models['storage']->where('subject_type', '=', 'property_photo')->get()->each(function ($photo) use (&$models) {
if ($photo->subject_name == 'CondoProperty') {
//...
}
//...
});
Run Code Online (Sandbox Code Playgroud)
请记住,您还可以运行DB::disableQueryLog();以节省大型数据库操作的内存。