問題情境:
公司有100W+的資料要提交給第三方平台,第三方平台要求使用XML的檔案格式(上傳時可以壓縮成gz格式),但也要求把所有的資料寫入一個XML檔案,不可以分割;
我的做法是將資料寫入到$dom對象裡,最後統一 $dom->save($xmlFile); 這種方式佔用記憶體太大,而且100W+的產品寫入操作完成需要很長的時間。
我想請問一下各位大拿,有沒有更好的建議,可以減少記憶體佔用,以及縮短Job執行時間的方法呢?
非常感謝~~~
回複內容:
問題情境:
公司有100W+的資料要提交給第三方平台,第三方平台要求使用XML的檔案格式(上傳時可以壓縮成gz格式),但也要求把所有的資料寫入一個XML檔案,不可以分割;
我的做法是將資料寫入到$dom對象裡,最後統一 $dom->save($xmlFile); 這種方式佔用記憶體太大,而且100W+的產品寫入操作完成需要很長的時間。
我想請問一下各位大拿,有沒有更好的建議,可以減少記憶體佔用,以及縮短Job執行時間的方法呢?
非常感謝~~~
試試這個思路可以嗎? http://phpedia.net/1v2knpye
- 記憶體虛擬成一塊硬碟,然後寫入你的記憶體硬碟
- 拿到一個資料就寫入file,而不是拿到所有資料才寫人
- 如果xml結構不複雜的話,用字串拼接 往往比使用xml庫來匯出xml資料要快很多。
- 換別的語言試試,php對檔案I/O的操作是很慢的。
用dom就必須把所有的資料全部放到記憶體裡面
我覺得直接用字串拼xml會很快,而且拼好一塊就append到檔案裡面,應該會快很多
為何不考慮json格式呢?解析儲存傳輸都比xml格式的有優勢。
而且php支援json和xml格式的互相轉換。
但100w+的資料沒有測試過轉換的耗費多少。
這個需求中,寫入一個XML檔案並不是必須的。
值得考慮用流水線式的模型解決問題。上傳資料不需要非得等XML全產生完了才開始,而是只需產生一點XML就上傳一點。
gzip也是一個純粹流式的壓縮(進來一點就出去一點),所以gzip也可以簡單插入到這個操作流之中。
無論如何提交,100W都很考驗網路連接的品質和對方API平台的處理能力,請首先儘可能找到分批提交的辦法。
不是有xmlreader 和 xmlwriter 嗎?可以不斷讀取Xml文檔中的聲明,節點,且不會一次載入.
file_put_contents($fileName, $contents, FILE_APPEND);
追加沒有任何問題,webserver log日誌比這個大多了
樓主這是要做feed檔案吧,我也做過,數量級比你大得多,我是用php直接拼接xml的,不用類。
簡單說是將大任務割成小任務,分次處理,不存在記憶體不夠之類的問題。
方法如下:
$total 一共有多少記錄
$batch 一次處理多少記錄
ceil($total/$batch)得到處理次數
將這些資料用ajax請求方式,一次又一次地調用,每次都往後處理一批資料,資料寫入就用:
file_put_contents($fileName, $contents, FILE_APPEND); 這個方法,前面 @tohilary 已經說了,我這正好也是用的這種方式,一次產生G級檔案沒問題,我還寫了個進度條,效果像這樣
1.每次都使用LIMIT 0,100來取資料(每次都取前100條),這樣不會因為頁數大而導致從資料庫拉取資料分頁慢【這樣操作很快】
2.使用100個多線程+innodb事務進行對操作過的資料進行標記,如:isWrite=1(代表已經寫入檔案了)
如上所述,每次可以執行100*100=1W條資料,執行100批,file_put_contents($fileName, $contents, FILE_APPEND);產生100個節點檔案【這樣操作需要等一會...】
3.最後一步,把上述100個XML節點檔案合并成為1個大XML檔案即可,可以用shell命令:copy /b *.xml all.xml【這樣操作很快】
具體事務請參考 Mysql Innodb 事務在業務中的具體使用案例 + Demo示範
我擔心的是你記憶體佔用太多,會很慢啊