将大量数据百万级导出到csv。由于数据量大,仅扩大内存仍会报错。
百万级的数据从数据库中查询,若不分段查或不刷新缓冲区,均会出错。
分段从数据库中查询再定期刷新缓冲区的方法。
set_time_limit(0);//让程序一直运行
ini_set('memory_limit', '128M');//设置临时内存
$fileName = '测试导出数据';//导出文件名
header('Content-Encoding: UTF-8');
header("Content-type:application/vnd.ms-excel;charset=UTF-8");
header('Content-Disposition: attachment;filename="' . $fileName . '.csv"');
$fp = fopen('php://output', 'a');
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));//bom防乱码
fputcsv($fp, ['title1', 'title2', 'title3']);//表头
require_once '../class/db.class.php';
$obj=new db();
$sqlBefore="select id from setting_item where 1 ";
$count=$obj->getNumRow($sqlBefore);
$nums=10000;//每次导出数量
$step=ceil($count/$nums);//循环次数
for($i = 0; $i < $step; $i++) {
  $start = $i * 10000;
  $sql=str_replace("id", "*", $sqlBefore)." LIMIT {$start},{$nums}";
  //echo $sql;
  $q=$obj->getAll3($sql);
  while($item=$q->fetch_array(MYSQLI_USE_RESULT)){
  //print_r($item);
    fputcsv($fp, $item);
  }
  //每1万条数据就刷新缓冲区
  ob_flush();
  flush();
}//for
13万条数据,导出时间7s。
默认不是文本,如001会被存在1,6/7会被保存成6月7日等,解决方案是统一保存成文本格式,导出变量加\t,如下:
$item["size"]="\t".$item["size"];