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