一、需求

项目需要,需要在后台导入数据,从 csv 中读取数据并写入数据表中。

csv 的数据可能是百万条的,因此需要对其进行处理,在 Laravel 中进行一次性百万数据的写入。

二、进行 sql 的拼接

主要实现的方式使用的是:拼接 sql 一次性执行的方式。

下面的方法是将 data 数组循环拼接成 sql 语句进行执行,至于 data 的组成不是很重要。

关键点是 sql 的拼接部分,最终实现的sql 结果是:

INSERT INTO `jzxsjfx_patient` (`pid`, `hospital`, `name`, `sex`, `birthday`, `age`, `created_at`, `updated_at`, `deleted_at`) VALUES
('10003', '', '谢**', '男  ','1900年1月0日', '75', '2018-04-16 04:43:00','2018-04-16 04:43:00', NULL),
('10063', '', '虞**', '男  ','20700', '61', '2018-04-16 04:43:00','2018-04-16 04:43:00', NULL),
('10097', 'z168146', '张**', '男  ','1900年1月0日', '64', '2018-04-16 04:43:00','2018-04-16 04:43:00', NULL),
('10113', '', '李**', '男  ','1900年1月0日', '73', '2018-04-16 04:43:00','2018-04-16 04:43:00', NULL),
('10138', '', '熊**', '男  ','1900年1月0日', '55', '2018-04-16 04:43:00','2018-04-16 04:43:00', NULL),
('10806', 'z290997', '施**', '男  ','20553', '61', '2018-04-16 04:43:00','2018-04-16 04:43:00', NULL)

将 sql 返回之后,通过 DB 类 一次执行原生的 sql 就行。

  /**
   * @title createdAllInSql
   * @description 将所有的数据拼接成sql语句
   * @author postbird
   * @param $data
   * @return bool|string
   */
  protected function createdAllInSql($data){
    $sql = '';
    $prefix = Config::get('database.connections.mysql.prefix');
    $dateTime = date('Y-m-d H:i:s');
    $sql = "INSERT INTO `".$prefix."patient` (`pid`, `hospital`, `name`, `sex`, `birthday`, `age`, `created_at`, `updated_at`, `deleted_at`) VALUES";
    foreach ($data as $item){
      $pid = (string)$item['医疗卡号'];
      $hospital = (string)$item['住院号'];
      $name = (string)$item['姓名'];
      $sex = (string)$item['性别'];
      $birthday = (string)$item['生日'];
      $age = $item['年龄'];
      $sql .= "('$pid', '$hospital', '$name', '$sex','$birthday', '$age', '$dateTime','$dateTime', NULL),";
    }
    $sql = substr($sql,0,strlen($sql)-1);
//    dd($sql);
    return $sql;
  }

三、写入数据表中

写入数据表的时候,使用的是原生 sql 写入,因此使用的方式是 DB::insert($sql)

      // 拼接sql语句写入数据库中
      $sql = $this->createdAllInSql($data);
      $res = DB::insert($sql);

测试的时候,导入 30W 数据耗时是 4s

四、可能出现的错误

因为写入的数据过多,可能会出现下面错误:

MySQL server has gone away

解决方法,可以在 mysql 控制台中或者是任何能够执行 sql 语句的地方执行:

set global max_allowed_packet=2*1024*1024*1024;