1. 程式人生 > >ef+Npoi匯出百萬行excel之踩坑記

ef+Npoi匯出百萬行excel之踩坑記

        最近在做一個需求是匯出較大的excel,本文是記錄我在做需求過程中遇到的幾個問題和解題方法,給大家分享一下,一來可以幫助同樣遇到問題的朋友,二呢,各位大神也許有更好的方法可以指點小弟一下,讓我順便學習一下。 背景::工頭:“小鐘啊,xx介面加個匯出excel功能03以後的格式,需要能支援到excel的最大行,同時需要5個併發就行” 我:“收到,但是資料大的時候速度可能比較慢。” 工頭:“你先做後續客戶反饋了在給他加進度條。” Npoi神器介紹:SXSSFWorkbook 專門用來匯出大資料用,他會把資料先寫入C盤的臨時目錄;不會所有 都留在記憶體裡;更詳細介紹請百度或者參考(http://poi.apache.org/components/spreadsheet/how-to.html#sxssf) 有了這層基礎開始劈里啪啦一段操作寫程式碼;(以下程式碼非生產程式碼只是我為了帖子寫重現問題的測試程式碼) 首先開個執行緒模擬併發 編寫匯出方法:記錄時間、建立SXSSFWorkbook 程式碼如圖: 啟動執行; 好!第一口鍋已造好,看這個提示,前面說了SXSSFWorkbook 是會先把快取資料寫入Windows臨時檔案裡頭的,這個目錄正好是Windows的臨時資料夾雖然是個錯誤但是驗證了剛剛的說法;至於這個錯誤看提示 我們有個大膽的想法是檔案佔用問題,應該是建立檔案的時候檔案已經存在了,這樣我們把npoi的dll開啟來看看,通過看原始碼和各種f12我們看到了這麼一段程式碼 這裡看到用來隨機數,而我們知道net的隨機數在極短的時間內生成是不可靠的(詳見百度或者: https://docs.microsoft.com/zh-cn/dotnet/api/system.random.-ctor?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev16.query%3FappId%3DDev16IDEF1%26l%3DZH-CN%26k%3Dk(System.Random.%2523ctor);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.0);k(DevLang-csharp)%26rd%3Dtrue&view=netframework-4.8)也就是說生成一樣的檔名,然後我們在通過 github裡可以看到
  早在年初NPOI就對這個問題做了更改就換成guid了,隨後我來到了nuget nuget最新版 是去年12月份釋出,並沒有包含上面的更改; 所以呢 要麼github下載最新版編譯要麼自己解決,想了想如果換版本的話以前的功能可能會影響到所以,我們就在外面加一把小鎖吧!如圖   這樣呢我們在試試!   很好 不會在出現檔案佔用問題了;好繼續匯出! 既然是都先寫入快取檔案是不是佔用的記憶體就很小了 來看看 2G多。。。什麼情況,還在漲   3G。。。這明顯不符合工頭的需求了,然後終於它炸了 第一念頭是為啥我該怎麼辦,設定GC的回收模式?手動多GC?還是要把程式碼給拿下來看看,看看這麼大記憶體哪裡沒釋放檔案?冷靜、冷靜、想想,既然是記憶體爆了 那麼正確流程應該是抓取看看是什麼吃的記憶體得出結果再去改東西,
發現了啥是不是很熟悉的東西? 狀態管理、包裝類,想到了啥 EF的“模型跟蹤”這個功能佔用的記憶體最大了。那就去掉吧 加上這麼一句 意思是無跟蹤查詢 ,修改例項後SaveChanges不對對它生效; (AsNoTracking 更詳情理解介紹請百度在加上msdn:https://docs.microsoft.com/zh-cn/ef/ef6/querying/no-tracking?redirectedfrom=MSDN ) 現在在繼續匯出看看: 記憶體是吃的不大了, 可以看出臨時檔案還是很大的,這還沒導完呢,所以做的時候 儘量要保證下硬碟的空間! 等待。。。 總結: 1.匯出大資料用SXSSFWorkbook 2.構建SXSSFWorkbook 時候lock或者自己編譯最新版本 3.我們做匯出時,ef查詢資料後記得加AsNoTracking 關閉繫結跟蹤。(以後日常開發中如果只需要查詢的也可以這樣做) 4.SXSSFWorkbook 匯出大資料 臨時資料夾所在的硬碟不能太小 因為會生成大於excel本身的快取檔案!
    最後匯出完畢 用時: