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 协议》,转载必须注明作者和本文链接
知者不惑,仁者不忧,勇者不惧。
本帖由系统于 8个月前 自动加精
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 46

@诺大的院子 加上事务为什么会快啊?

10个月前 评论
AppModel::query()->insert([
  ['name'=>'111'],
  ['name'=>'222']
]);

这样不能批量添加?

10个月前 评论
shaolin (作者) 10个月前
shaolin (作者) 10个月前
huangxu (楼主) 10个月前
huangxu (楼主) 10个月前
huangxu (楼主) 10个月前
laradocs 10个月前

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

10个月前 评论
吃鱼不吐刺 (作者) 10个月前
huangxu (楼主) 10个月前
huangxu (楼主) 10个月前
mysql cli source 100w.sql  🐶
10个月前 评论
huangxu (楼主) 10个月前
心语难诉 10个月前

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

另外

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

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

10个月前 评论
mowangjuanzi 6个月前

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

10个月前 评论
huangxu (楼主) 10个月前

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

9个月前 评论
huangxu (楼主) 9个月前

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

file

9个月前 评论
shaolin 9个月前
shaolin 9个月前
shaolin 9个月前
SmileVV (作者) 9个月前
shaolin 9个月前
SmileVV (作者) 9个月前
shaolin 9个月前
shaolin 9个月前
SmileVV (作者) 9个月前
SmileVV (作者) 9个月前
SmileVV (作者) 9个月前
飞飞鱼 9个月前

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

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

9个月前 评论
huangxu (楼主) 9个月前
Yoooooo 7个月前

技术文章也开始标题党了

9个月前 评论
huangxu (楼主) 9个月前

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

9个月前 评论
huangxu (楼主) 9个月前
Yoooooo 7个月前

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

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());
}
4个月前 评论

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