Php 更新Laravel中大量条目的最佳方法
我有一份来自供应商的文件,它给了我所有时间的库存更新。我想在我的数据库中每小时进行一次更新,问题是任务太重,页面在大约10秒后加载,因为它包含将近10.000个条目 以下是我的供应商提供的文件:Php 更新Laravel中大量条目的最佳方法,php,laravel,performance,Php,Laravel,Performance,我有一份来自供应商的文件,它给了我所有时间的库存更新。我想在我的数据库中每小时进行一次更新,问题是任务太重,页面在大约10秒后加载,因为它包含将近10.000个条目 以下是我的供应商提供的文件: stock.csv ref, qty XXX01, 5 XXX02, 10 XXX03, 3 XXX04, 8 XXX05, 6 ... 我得到这个文件,并使用这个神奇的库将其转换为数组: 结果是: Array 0 => ['ref' => XXX01, 'qty' => 5] 1
stock.csv
ref, qty
XXX01, 5
XXX02, 10
XXX03, 3
XXX04, 8
XXX05, 6
...
我得到这个文件,并使用这个神奇的库将其转换为数组:
结果是:
Array
0 => ['ref' => XXX01, 'qty' => 5]
1 => ['ref' => XXX02, 'qty' => 10]
2 => ['ref' => XXX03, 'qty' => 3]
...
然后我做一个foreach循环来更新数据库中的每个项目
我的
items
表如下所示:
id, ref, (...), qty
1, XXX01, 0
2, XXX02, 3
3, XXX03, 1
4, XXX04, 2
5, XXX05, 0
这是我的密码:
// convert .csv into Array
$path = public_path('stock').'/stock.csv';
Excel::setDelimiter(',');
$data = Excel::load($path, function($reader){})->get()->toArray();
// make it in Laravel Collection
$stocks = new Collection($data);
// The treatment
foreach ($stocks as $stock){
$item = Item::where('ref', $stock['ref'])->first();
$item->qty = $stock['qty];
$item->save();
}
// Too long...
Laravel中是否有其他选项可以使其速度更快?在不检索记录的情况下更新行肯定会节省大量查询:
foreach ($stocks as $stock){
Item::where('ref', $stock['ref'])->update(['qty' => $stock['qty']]);
}
如果您经常有很多相同的数量,那么将它们分组可能会更快:
foreach($stocks->groupBy('qty') as $qty => $stocks) {
Item::whereIn('ref', $stocks->pluck('ref'))->update(['qty' => $qty]);
}
在不检索记录的情况下更新行肯定会节省大量查询:
foreach ($stocks as $stock){
Item::where('ref', $stock['ref'])->update(['qty' => $stock['qty']]);
}
如果您经常有很多相同的数量,那么将它们分组可能会更快:
foreach($stocks->groupBy('qty') as $qty => $stocks) {
Item::whereIn('ref', $stocks->pluck('ref'))->update(['qty' => $qty]);
}
正如Devon提到的,您可以直接更新,而无需检索记录。显著提高更新速度的另一种方法是使用事务 您可以通过执行
try{
DB::transaction(function(){
//make your updates here
});
}catch(\Exception $e){
//gone wrong...
});
如果没有引发异常,它将自动提交(=保存您的更改),否则它将回滚您的更改
这里有两大优势
首先,在transaction()
方法中,与数据库写入(插入/更新)相关的所有内容都会更快
第二个优点是,如果出现错误(根据我的经验,通过文件进行大规模插入/更新经常会出错),您的更改将不会提交:它们不会保存到数据库中
您可以找到Laravel关于交易的文档
编辑
因为我们主要讨论的是纯速度,所以我没有讨论排队作业,但是包含大量数据的文件导入/导出非常适合此功能的用途。您的脚本执行速度不会更快,但您不会在等待它完成时陷入困境,它将在另一个进程中运行。关于作业的文档正如德文所提到的,您可以直接更新,而无需检索记录。显著提高更新速度的另一种方法是使用事务 您可以通过执行
try{
DB::transaction(function(){
//make your updates here
});
}catch(\Exception $e){
//gone wrong...
});
如果没有引发异常,它将自动提交(=保存您的更改),否则它将回滚您的更改
这里有两大优势
首先,在transaction()
方法中,与数据库写入(插入/更新)相关的所有内容都会更快
第二个优点是,如果出现错误(根据我的经验,通过文件进行大规模插入/更新经常会出错),您的更改将不会提交:它们不会保存到数据库中
您可以找到Laravel关于交易的文档
编辑
因为我们主要讨论的是纯速度,所以我没有讨论排队作业,但是包含大量数据的文件导入/导出非常适合此功能的用途。您的脚本执行速度不会更快,但您不会在等待它完成时陷入困境,它将在另一个进程中运行。有关乔布斯的文档谢谢
@托伊和德文郡
这是我的新代码
$path = public_path('stocks').'/tyce_stocks.csv';
Excel::setDelimiter(',');
$data = Excel::load($path, function($reader){})->get()->toArray();
$stocks = new Collection($data);
try{
DB::transaction(function() use ($stocks) {
foreach ($stocks as $stock){
DB::table('items')
->where('ref', $stock['ref'])
->update(['qty' => $stock['qty]]);
}
});
}catch(\Throwable $e){
// send mail with error
};
它速度更快,页面不会崩溃,而且我在每天凌晨1:00和下午1:00运行的作业计划中工作
$schedule->command('stock:update')->twiceDaily(1, 13);
谢谢 谢谢
@托伊和德文郡
这是我的新代码
$path = public_path('stocks').'/tyce_stocks.csv';
Excel::setDelimiter(',');
$data = Excel::load($path, function($reader){})->get()->toArray();
$stocks = new Collection($data);
try{
DB::transaction(function() use ($stocks) {
foreach ($stocks as $stock){
DB::table('items')
->where('ref', $stock['ref'])
->update(['qty' => $stock['qty]]);
}
});
}catch(\Throwable $e){
// send mail with error
};
它速度更快,页面不会崩溃,而且我在每天凌晨1:00和下午1:00运行的作业计划中工作
$schedule->command('stock:update')->twiceDaily(1, 13);
谢谢 会有帮助吗?您是否尝试过不使用Excel,这将需要大量资源,而且根本不是该软件包的目的
str_getcsv
应该快得多。会有帮助吗?您是否尝试过不使用Excel,这将需要大量资源,而且根本不是该软件包的目的str_getcsv
应该快得多。将它们组合到单个事务中肯定是一种速度提升。将它们组合到单个事务中肯定是一种速度提升。