如何为 Laravel 优化超大数据的导入过程?
Posted
技术标签:
【中文标题】如何为 Laravel 优化超大数据的导入过程?【英文标题】:How to Optimize Import Process for very large data for Laravel? 【发布时间】:2019-10-20 21:09:52 【问题描述】:我可以导入大约 500 万条记录。
我还必须在导入过程中同时为相关表创建条目。
我必须对新条目进行成组插入查询,并处理所有查询并分块进行处理。
还有哪些其他方法可以加快进程?
【问题讨论】:
Redis 是什么?我已经检查过了。但拿不到。 批处理作业可能会有所帮助,但内存可能会很有挑战性 也许使用一个单独的队列服务器,它只是缓慢地运行作业?可以使用 redis。 可以理解。查询很简单,是但不是整个操作。使用 DB 门面可能会更快,因为您可以使用 insert 方法一次插入多条记录。 对于初学者,不要与 API 进程同步。它可能会并且需要超过 10 秒。 IMO,将文件转储到临时存储(s3 或磁盘上)。使用 Laravel Job,触发插入过程。在 UI 方面,显示一个加载器。在数据库中维护与流程相关的(处理的数量)。您的问题不应该是“如何优化 Eloquent 查询”,而是“如何优化流程” 【参考方案1】:用途:
在块中处理数据 使用 Laravel 队列
使用https://docs.laravel-excel.com/3.1/imports/ 用户模型绑定示例
namespace App\Imports;
use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
class UsersImport implements ToModel
use Importable;
public function model(array $row)
return new User([
'name' => $row[0],
'email' => $row[1],
'password' => Hash::make($row[2]),
]);
在控制器中
(new UsersImport)->import('users.xlsx', 'local', \Maatwebsite\Excel\Excel::XLSX);
【讨论】:
请提供问题相关链接中的相关代码。避免使用外部链接,这样即使链接失效.. 我们在答案中也有信息 Laravel excel 对于大数据不是那么灵活。我已经尝试过 laravel excel。 我将它用于批量处理,它有许多新功能,如事务、队列、块处理、模型绑定,这是验证和插入最重要的功能,还提供自定义集成。我同意 excel 不是那么灵活,但 laravel-excel 让你更容易 @VivekSolanki 你用过哪个版本?你能分享任何问题陈述,以便我分享我的反馈。 @VivekSolanki 如果速度是问题,那么您应该改用 CSV,但是模型绑定有助于实现更好的速度。【参考方案2】:所以总结一下那些不费心单独查看所有cmets的人:
使用 Laravel 提供的 DB 外观而不是 improved performance 的 Eloquent 模型。 批量运行导入过程,而不是一次导入所有数据。 Disble query logging 以节省内存使用量。 在后台作业中运行导入,而不是在 Web 请求期间。除了已经提出的要点,您还可以考虑:
首先运行一个作业,以 50 行(或其他一些合理的数字)为单位读取您的输入 xlsx/csv 文件。确保不要将所有行都保存在内存中。然后为每批生产线创建一个新作业。因此,您将进行两步导入。 为每个批次创建单独的作业时,您可以同时运行这些作业(= 同时运行多个队列工作器)。 如果您有用户等待导入完成,请确保显示进度条或至少显示某种动画加载器。虽然这不会加快进程,但它会给他们一个指示,工作正在完成。 您还可以利用 database transactions 一次运行多个数据库查询(此操作归功于 Philippe Thiers)【讨论】:
我已经为我的进程尝试了队列。但不是同时运行,而是一个接一个地执行。 您必须同时运行多个命令行才能执行此操作。在生产环境中Supervisor is advised。这是一个使某些进程(在您的情况下为队列工作程序)始终运行的工具。如果作业失败、错误或内存不足并停止,它将由主管重新启动。主管的配置允许您指定numprocs
,即同时处理的进程数。
加入列表,使用事务,DB::transaction(closure);
或\DB::beginTransaction; try /* code */ \Db::commit; catch(\Exception $e) \Db::rollback;
【参考方案3】:
(从 laracasts 复制) 这可能也会有所帮助:
DB::connection()->disableQueryLog();
"默认情况下,Laravel 会在内存中记录为当前请求运行的所有查询。但是,在某些情况下,例如插入大量行时,这可能会导致应用程序使用过多的内存。”
【讨论】:
这是给Laravel <= 4.2
的,在以后的版本中它默认被禁用...所以它不会影响laravel 5.8
问题要求中提到的。以上是关于如何为 Laravel 优化超大数据的导入过程?的主要内容,如果未能解决你的问题,请参考以下文章
应该如何为 laravel 4 composer 包设置 git 子模块?
如何为每个商店自动增加特定的数据库表值。 (Laravel 6)