laravel实现100w大量数据插入数据库

laravel实现100w大量数据插入数据库

在使用laravel eloquent进行数据库操作的时候惊讶的发现这货居然不支持批量添加,看到网上很多人在循环里进行数据库插入操作来实现批量添加,我想说这样做是很损失性能滴!好在框架的DB门面里的insert方法可以进行批量插入。

$data= [
  ['name'=>'111'],
  ['name'=>'222'],
];
DB::table('xxx')->insert($data);

但是我的数据有点多,100w条数据需要导入数据库,一条条插入,需要好久的时间。原生sql可以实现拼接语句实现批量执行达到快速导入的效果。在laravel框架中貌似要自己实现,查找发现集合的chunk方法实现数据分块处理,达到组装批量插入效果。代码如下:

 set_time_limit(0);

 try {
    //上传文件位置,这里默认是在storage中,如有修改请对应替换
    $file = storage_path('/app/public/' . $input['file']);
    $domain = [];
    foreach($this->readTxt($file) as $key=>$line) {
        $domain[$key] = $line;
    }
    //数组分块处理
    $chunck = collect($domain);
    $chunks = $chunck->chunk(1000);
    $chunks->all();
    foreach ($chunks as $key=>$val){
        $arr = [];
        foreach ($val as $k =>$value){
            $arr[$k]['domain'] = $value;
            $arr[$k]['created_at'] = date('Y-m-d H:i:s');
        }
        DB::table('domain')->insert($arr);
   }
 }catch (\Exception $e) {
    return $this->response()->error($e->getMessage());
 }

读文件使用的方法:

  public function readTxt($path)
    {
        $file = fopen($path, "r");
        //输出文本中所有的行,直到文件结束为止。
        while (!feof($file)) {
            yield trim(fgets($file));  //迭代器,
        }
        fclose($file);
    }
本作品采用《CC 协议》,转载必须注明作者和本文链接
知者不惑,仁者不忧,勇者不惧。
本帖由系统于 2年前 自动加精
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 50
mysql cli source 100w.sql  🐶
2年前 评论
huangxu (楼主) 2年前
心语难诉 2年前
猫巷 4个月前
mysql cli source 100w.sql  🐶
2年前 评论
huangxu (楼主) 2年前
心语难诉 2年前
猫巷 4个月前

先关闭数据库的 autocommit,再用 LazyCollection,然后再根据内存情况选择每次插入的量,最后批量插入

另外

MySQL 自带的 LOAD DATA 指令轻轻松松加载千万级别的数据

dev.mysql.com/doc/refman/8.0/en/lo...

2年前 评论
mowangjuanzi 2年前

所以你这样插入100万条花了多久时间?

2年前 评论
吃鱼不吐刺 (作者) 2年前
huangxu (楼主) 2年前
huangxu (楼主) 2年前

数据读取有内存过大的风险 建议用生成器

2年前 评论
huangxu (楼主) 2年前
冯小胖同学 (作者) 11个月前

有点狠,100W行的文件读出来,放到php数组,光这一步估计内存就要扛不住了,再把数组转换成collection对象,想想都可怕......

建议使用生成器读取文件,读取同时分批生成collection或者分批写入数据库,这样稍微好些

2年前 评论
huangxu (楼主) 2年前
Diudiuuuu 2年前

下面只是我看代码的分析,没有做实际测试

file

et_time_limit(0);

try {
    //上传文件位置,这里默认是在storage中,如有修改请对应替换

    //数组分块处理
    $chunks = (new LazyCollection(function () use ($input) {
//                懒加载集合生成方法
        $file = storage_path('/app/public/' . $input['file']);
        $h    = fopen($file, 'r');
        while (!feof($h)) {
            yield trim(fgets($h));
        }
        fclose($h);
    }))->chunk(1000)->each(function ($item) {
//                批量插入
        DB::table('')->insert($item->map(function ($val) {
            // 各种处理
            return $val;
        }));
    });
} catch (\Exception $e) {
    return $this->response()->error($e->getMessage());
}
1年前 评论
AppModel::query()->insert([
  ['name'=>'111'],
  ['name'=>'222']
]);

这样不能批量添加?

2年前 评论
shaolin (作者) 2年前
shaolin (作者) 2年前
huangxu (楼主) 2年前
huangxu (楼主) 2年前
huangxu (楼主) 2年前
laradocs 2年前

两万的数据 分块(1000)插入数据库 时间一分钟多直接报超时 怎么解决

2年前 评论
huangxu (楼主) 2年前

@huangxu 是这样的 麻烦看一下是否还有优化空间 谢谢

file

2年前 评论
shaolin 2年前
shaolin 2年前
shaolin 2年前
SmileVV (作者) 2年前
shaolin 2年前
SmileVV (作者) 2年前
shaolin 2年前
shaolin 2年前
SmileVV (作者) 2年前
SmileVV (作者) 2年前
SmileVV (作者) 2年前
飞飞鱼 2年前

技术文章也开始标题党了

2年前 评论
huangxu (楼主) 2年前

代码的意思是100W行数据要放在数据?确定内存没压力吗

2年前 评论
huangxu (楼主) 2年前
Diudiuuuu 2年前

你这不还是长时间占用I/O开销。这也算方法!!!

1年前 评论
huangxu (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!