開發中經常遇到這樣的場景
產品汪:我要在後台做乙個功能,可以匯出自定義時間範圍的訂單資訊。開發小哥二話不說,半天就把功能做完並上線了。結果,第二天一上班產品汪過來就是拍桌子:md,我想把去年一整年的訂單都匯出來,結果後台直接就掛了!
開發小哥一查,原來是記憶體溢位了,一年下來的的訂單量足足有1000w條。於是,開發小哥跟產品汪吵了起來:你tm色不色傻,1000w的資料你匯出來幹diao,你是不是想把伺服器給搞掛掉?
於是,產品汪與程式狗就這麼結下樑子了。
但是。產品的需求你敢這樣懟回去,那如果是老闆提的這個需求呢,就是硬要把1000w條記錄匯出來,你還不得乖乖回去碼**?
那麼,這個如果真要匯出這大量資料,該怎麼做呢?開發中我們經常會使用框架來提高我們的開發效率,但也意味著框架會對一些資料進行封裝。
比如yii2,當我們想獲取去年一年的訂單時,我們的**會這樣寫:
order::find()->where(「create_time between 『2016-01-01』 and 『2016-12-31』」)->all();
當我們將上面**得到的結果集再拿去遍歷時,資料量一大,就會記憶體溢位。
原因是:yii2中,對all方法進行了封將,將大量的資料存入了陣列中,而遍歷大資料,必然會導致記憶體迅速上公升。
那如何取出大量資料,而又不存到陣列中呢?這就要用到了php中的迭代器:iterator。如果有看過pdo::query的返回值型別的話,我們會發現,這個方法返回的pdostatement,正是對 iterator 的實現。關於 iterator,請自行腦補。
即然框架幫我們做了多餘的封裝,那麼我們就改用原生api來實現。以下是完整**
$sql = 'select * from user';
$pdo = new \pdo('mysql:host=127.0.0.1;dbname=test', 'root', 'root');
$pdo->setattribute(\pdo::mysql_attr_use_buffered_query, false);
$rows = $pdo->query($sql);
$filename = date('ymd') . '.csv'; //設定檔名
header('content-type: text/csv');
header("content-disposition: attachment;filename=");
$out = fopen('php://output', 'w');
fputcsv($out, ['id', 'username', 'password', 'create_time']);
foreach ($rows as $row)
fclose($out);
$memory = round((memory_get_usage() - $startmemory) / 1024 / 1024, 3) . 'm' . php_eol;
在表中生成7位數量級的記錄,執行上面的**,通過檢視記憶體使用,發現整個過程只占用了0.xm的記憶體,完全沒有任何記憶體溢位的現象。 PHP MYSQL 查詢大資料 遍歷表
php php 5.3.6 cli built jun 15 2011 16 29 50 mysql 5.1.51 如果我們有的一張表有幾百萬或幾千萬的記錄,我們要使用 php 將所有的記錄都獲取過來 遍歷資料表 進行處理。查詢語句 select from largetable ps 為了證明上面的...
大資料匯出2
經過幾天的折騰,終於把這個頑固的工程做完了,現在60萬資料40秒匯出到本地。嘗試了很多的辦法,現在放上最優秀的做法供參考。第一,優化資料表,加上相應的索引,分割槽。第二,讀庫操作。分多執行緒,採用threadpool。第三,匯出操作,1 採用aspose.cells 2 採用多檔案方式,要麼以記錄行...
POI 大資料匯出
gradle 匯入 org.apache.poi poi ooxml 3.14 poi對excel的匯出操作,一般只使用hssfworkbook以及sxssfworkbook hssfworkbook用來處理較少的資料量,sxssfworkbook用來處理超大資料量的匯出,20w資料沒什麼問題。注意...