摘要:而常用的包需要把所有數據拿到后才能生成,在面對生成超大數據量的文件時這顯然是會造成內存溢出的,所以考慮使用讓邊寫入輸出流邊讓瀏覽器下載的形式來完成需求。
最近接到一個需求,通過選擇的時間段導出對應的用戶訪問日志到excel中, 由于用戶量較大,經常會有導出50萬加數據的情況。而常用的PHPexcel包需要把所有數據拿到后才能生成excel, 在面對生成超大數據量的excel文件時這顯然是會造成內存溢出的,所以考慮使用讓PHP邊寫入輸出流邊讓瀏覽器下載的形式來完成需求。
我們通過如下的方式寫入PHP輸出流
$fp = fopen("php://output", "a"); fputs($fp, "strings"); .... .... fclose($fp)
php://output是一個可寫的輸出流,允許程序像操作文件一樣將輸出寫入到輸出流中,PHP會把輸出流中的內容發送給web服務器并返回給發起請求的瀏覽器
另外由于excel數據是從數據庫里逐步讀出然后寫入輸出流的所以需要將PHP的執行時間設長一點(默認30秒)set_time_limit(0)不對PHP執行時間做限制。
注:以下代碼只是闡明生成大數據量EXCEL的思路和步驟,并且在去掉項目業務代碼后程序有語法錯誤不能拿來直接運行,請根據自己的需求填充對應的業務代碼!
/** * 文章訪問日志 * 下載的日志文件通常很大, 所以先設置csv相關的Header頭, 然后打開 * PHP output流, 漸進式的往output流中寫入數據, 寫到一定量后將系統緩沖沖刷到響應中 * 避免緩沖溢出 */ public function articleAccessLog($timeStart, $timeEnd) { set_time_limit(0); $columns = [ "文章ID", "文章標題", ...... ]; $csvFileName = "用戶日志" . $timeStart ."_". $timeEnd . ".xlsx"; //設置好告訴瀏覽器要下載excel文件的headers header("Content-Description: File Transfer"); header("Content-Type: application/vnd.ms-excel"); header("Content-Disposition: attachment; filename="". $fileName ."""); header("Expires: 0"); header("Cache-Control: must-revalidate"); header("Pragma: public"); $fp = fopen("php://output", "a");//打開output流 mb_convert_variables("GBK", "UTF-8", $columns); fputcsv($fp, $columns);//將數據格式化為CSV格式并寫入到output流中 $accessNum = "1000000"http://從數據庫獲取總量,假設是一百萬 $perSize = 1000;//每次查詢的條數 $pages = ceil($accessNum / $perSize); $lastId = 0; for($i = 1; $i <= $pages; $i++) { $accessLog = $logService->getArticleAccessLog($timeStart, $timeEnd, $lastId, $perSize); foreach($accessLog as $access) { $rowData = [ ......//每一行的數據 ]; mb_convert_variables("GBK", "UTF-8", $rowData); fputcsv($fp, $rowData); $lastId = $access->id; } unset($accessLog);//釋放變量的內存 //刷新輸出緩沖到瀏覽器 ob_flush(); flush();//必須同時使用 ob_flush() 和flush() 函數來刷新輸出緩沖。 } fclose($fp); exit(); }
好了, 其實很簡單,就是用逐步寫入輸出流并發送到瀏覽器讓瀏覽器去逐步下載整個文件,由于是逐步寫入的無法獲取文件的總體size所以就沒辦法通過設置header("Content-Length: $size");在下載前告訴瀏覽器這個文件有多大了。不過不影響整體的效果這里的核心問題是解決大文件的實時生成和下載。
更新: 說一下我數據庫查詢這里的思路,因為逐步寫入EXCEL的數據實際上來自Mysql的分頁查詢,大家知道其語法是LIMIT offset, num 不過隨著offset越來越大Mysql在每次分頁查詢時需要跳過的行數就越多,這會嚴重影響Mysql查詢的效率(包括MongoDB這樣的NoSQL也是不建議skip掉多條來取結果集),所以我采用LastId的方式來做分頁查詢。 類似下面的語句:
SELECT columns FROM `table_name` WHERE `created_at` >= "time range start" AND `created_at` <= "time range end" AND `id` < LastId ORDER BY `id` DESC LIMIT num
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/30697.html
摘要:四層負載均衡不會引起超時。動態修改包的目標地址,并轉發數據包使其到達不同的機器上來實現負載均衡的目的,因此節點不會引起超時。七層負載均衡等待上游響應超時。例如使用多線程并發減少遠程查詢的總體時間如需數據有序,可以使用方案。 B端業務經常要提供下載報表的功能,一般的方法是先查詢出所有數據,然后在內存中組裝成報表(如XLS/XLSX格式)后統一輸出。但是如果生成報表需要查詢的數據量很大,遠...
摘要:場景和痛點說明今天因為一個老同學找我,說自己公司的物流業務都是現在用處理,按月因為數據量大,一個差不多有百萬數據,文件有接近,打開和搜索就相當的慢聯想到場景要導入數據,可能數據量很大,這里利用常用的一些方法比如會常有時間和內存限制問題下面我 場景和痛點 說明 今天因為一個老同學找我,說自己公司的物流業務都是現在用excel處理,按月因為數據量大,一個excel差不多有百萬數據,文件有接...
關于 PHP 導出 excel csv 常用的有 PHPexcel ,本文整理了一些其他方案。 高性能 Excel 擴展 sudo apt-get install -y zlib1g-dev git clone https://github.com/jmcnamara/libxlsxwriter.git cd libxlsxwriter make && sudo make install // ...
摘要:場景和痛點說明我們工作場景都常會導出相關的數據,有時候需要大量的數據,,都有可能我們現有方案都是直接利用等類庫來操作,的加載或是寫入一次導出會遇到超時內存和時間限制問題,就算我們依舊不是最好的方案下面我們利用輸出,把數據依次輸出清空再輸出的 場景和痛點 說明 我們工作場景都常會導出相關的excel數據,有時候需要大量的數據,10W,100W都有可能我們現有方案都是直接利用phpexce...
摘要:使用好久了,好像今天才想起來要記一篇博客呢。之前一直用的框架,后來做接口的時候打算換成不料機緣巧合之下又結識了,于是乎決然的站到了的大營之下。今天小記一下這個類庫的常用操作。首先貼上地址,直接去下載最新版好了。 PHP使用好久了,好像今天才想起來要記一篇博客呢。之前一直用的 ci 框架,后來做接口的時候打算換成 tp5, 不料機緣巧合之下又結識了 node,于是乎決然的站到了 js 的...
閱讀 3488·2021-10-13 09:39
閱讀 1470·2021-10-08 10:05
閱讀 2276·2021-09-26 09:56
閱讀 2291·2021-09-03 10:28
閱讀 2690·2019-08-29 18:37
閱讀 2049·2019-08-29 17:07
閱讀 611·2019-08-29 16:23
閱讀 2200·2019-08-29 11:24