在項目中使用php批量導出資料到Excel中,大量資料2w,5w,10w資料就要面臨問題
1、導出時間變得很慢,少則1分鐘,多則好幾分鐘,資料量一旦上來,還可能面臨導不出來的困窘(這種導出效率正常人都會受不了,更何況是要求苛刻的使用者)。
2、導出消耗大量的記憶體資源,即使把php記憶體使用設定為無限大,當多個使用者同時使用導出功能導出大量資料的時候,伺服器記憶體使用就會直線往上升,報警,甚至當機,嚴重影響其他業務
需要注意EXCEL單表隻能顯示104W資料
解決思路大概是:
1、從資料庫中讀取要進行資料量分批讀取,以防變量記憶體溢出
2、選擇資料儲存檔案格式是csv檔案,以友善導出之後的閱讀、導入資料庫等操作
3、以防不友善excel讀取csv檔案,需要104W之前就得把資料分割進行多個csv檔案儲存
4、多個csv檔案輸出給使用者下載下傳是不友好的,還需要把多個csv檔案進行壓縮,最後提供給一個ZIP格式的壓縮包給使用者下載下傳就好。
直接上代碼
<?php
/*
*
* @param string $sql 需要導出的資料SQL
* @param string $mark 生成檔案的名字字首
* @param bool $is_multiple 是否要生成多個CSV檔案
* @param int $limit 每隔$limit行,重新整理輸出buffer,以及每個CSV檔案行數限制
*
*/
function putCsv($sql, $mark, $is_multiple=0, $limit=100000)
{
set_time_limit(0);
header('Content-Type: application/vnd.ms-excel;charset=utf-8');
header('Content-Disposition: attachment;filename="' . $mark . '"');
header('Cache-Control: max-age=0');
// 每隔$limit行,重新整理一下輸出buffer,也可以控制多csv檔案生成的行數限制
// buffer計數器
$file_num = 0; //檔案名計數器
$row_num = 0;
$fileNameArr = array();
// 逐行取出資料,不浪費記憶體
$fp = fopen($mark .'_'.$file_num .'.csv', 'w'); //生成臨時檔案
$fileNameArr[] = $mark .'_'.$file_num .'.csv';
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));//轉碼,防止亂碼
foreach (query($sql) as $a) {
$row_num++;
if ($limit <= $row_num) {
//重新整理一下輸出buffer,防止由于資料過多造成問題
if(ob_get_level()>0) ob_flush(); flush();
$row_num = 0;
$file_num++;
if($is_multiple>0){
fclose($fp); //每生成一個檔案關閉
$fp = fopen($mark .'_'.$file_num .'.csv', 'w');
$fileNameArr[] = $mark .'_'.$file_num .'.csv';
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));//轉碼,防止亂碼
}
}
fputcsv($fp, $a);
}
fclose($fp); //每生成一個檔案關閉
getZip('test',$fileNameArr); //生成zip檔案
}
$sql = 'SELECT id FROM `tablename` where id < 1200000';
$mark = 'test';//生成檔案字首
putCsv($sql,$mark);
?>
謝謝,ALL!