基本思路就是,知道總數之后分割成2萬一個數組進行查詢,最后獨立寫入csv,避免數據過大導致溢出
速度還不錯,在php7下,機器I5 8G內存,128G,SSD,52W多條,大概也就30秒,出來整個文件38.2M
$per = 10000; 37秒
$per = 20000; 34秒
$per = 30000; 的時候速度最快29秒左右
$per = 40000;30-31秒
所以建議在30000步幅,比較好,我的環境是windows 32位,64位或許會更好
建議導入文件過多就zip壓縮之后再下載
laravel 寫的demo 2018年6月19日18:13:26
$start = time(); set_time_limit(0); ini_set('memory_limit', '512M'); //獲取總數 $count = DataChinaYearData::count(); //526672 $per = 30000; $section = array(); for ($i = 0; $i <= $count; $i += $per) { $section[] = $i; } if (end($section) < $count) { $section[] = $count; } //清理輸出流的防止亂碼 ob_flush(); flush(); $fp = fopen('file.csv', 'w'); foreach ($section as $k => $v) { $list = array(); $list = DataChinaYearData::offset($v)->limit($per)->get()->toArray(); foreach ($list as $fields) { fputcsv($fp, $fields); } unset($list); //防止溢出 ob_flush(); flush(); } fclose($fp); $end = time(); $time = $end - $start; echo $time . '秒';
另一種懶人寫法,全部使用迭代器去操作
$start = time(); set_time_limit(0); $fp = fopen('file.csv', 'w'); foreach (new \ArrayObject(DataChinaYearData::get()->toarray()) as $k => $v) { fputcsv($fp, $v); } fclose($fp); $end = time(); $time = $end - $start; echo $time . '秒';
原理也很簡單,pdo就是迭代器,直接使用數組迭代器賦值,不使用變量接收就不會內存溢出
測試了2次,39秒和40秒,顯然這樣的速度就慢了一些,可以通過邏輯優化的就使用邏輯優化,純靠語言特性優化有時候是方便了寫代碼但是代碼思維邏輯就差多了
也可以通過使用迭代器接受超大數組,比如我需要讀取一個2G或者更大的文本文件或者excel,我直接按行讀取,然后全部放入迭代器中這樣不會出現內存溢出的情況
偽demo,有時間在寫個實際的demo
public static function test() { pp(self::get_array() instanceof \Generator); pp(self::get_array()); /* * Generator Object ( ) * */ foreach (self::get_array() as $k => $v) { p($k); p($v); } } public static function get_array() { $rr = array('0' => array('a' => 'aa'), '1' => array('a' => 'bb'), '2' => array('c' => 'cc'), '3' => array('d' => 'dd')); // $rr = array('0' => 'a', '1' => 'b', '2' => 'c', '3' => 'd'); foreach ($rr as $k => $v) { yield $k => $v; } }