同事分享的案例,也算是古蹟維護相關問題。

原本於 ASP.NET 2.0 網站運行多年的 RDLC 報表,在專案升級 ASP.NET 4.0 後有水土不服症狀:

  • 較複雜報表顯示時 CPU 飆高,吃掉整顆 CPU (同時預覽兩張報表甚至 CPU 100%)
  • 經交叉比對,記憶體使用量明顯較 ASP.NET 2.0 高
  • 報表產生速度嚴重變慢,ASP.NET 2.0 時代顯示報表只需幾秒,升到 ASP.NET 4.0 後要等 30 秒,有時還一片空白

MSDN 論壇有篇類似案例討論,情境為 Report Server 伺服器端報表改 RDLC, 使用 Fields!MyFieldName.Value 分群的報表正常,使用 Fields("MyFieldName").Value 動態欄位分群的報表速度慢八倍,且動態參數用愈多愈慢。即使資料筆數不多,用到一個動態參數 18 秒,用 4 個動態參數報表產生時間便超過一分鐘。

有位遭遇類似的網友,提供了寶貴解答,連絡微軟開發團隊協助檢視,得到的結論為:

關鍵在於 .NET 4.0 改變了 RDLC 的運作模式,Report Viewer 預設會將 Expression Evaluation 移到 Sandbox Domain 執行(參考:Expression Evaluation in Local Mode),好處是減少 Memory Leak 風險,代價則是會產生 Sandbox Domain 與應用程式 AppDomain 間的跨 Domain 溝通,形成效能瓶頸。這個效能問題與 .NET CAS 權限管控有關,有一些解決方法:

  • 避用動態表達示(如 Fields("MyFieldName").Value)或改用 .NET 3.5 (且不要啟用 ExecuteReportInSandboxAppDomain), 讓報表在應用程式的 AppDomain 執行可避開上述問題,但會提高 Memory Leak 風險且無法使用 .NET 4 功能。
  • 在 web.config 加入 <trust legacyCasModel="true" level="Full"/> 啟用舊版 CAS 模型,減緩因 CAS 管控產生的效能衝擊。 (可能有其他副作用,但這是 MS Team 提供的 Workaround 之一)

除了上述解法,我心中更好的做法是調整 RDLC 報表,把複雜的分群、彙整邏輯拉到 C# 端處理做出半成品,RDLC 只留簡單的呈現邏輯(註:子報表也很雷,要小心),相同邏輯用 C# 寫比用 RDLC 實現簡單,而且效能好 N 倍。MDSN 論壇討論中有類似建議 ( to replace the parts of the report definition that result in the extremely poor performance at runtime...including use of parameters in the grouping expression... ) ,這與同事在簡化報表可明顯提升速度的經驗吻合,符合三人成虎的門檻(咦?),在處理 RDLC 效能不佳問題時,可優先納入考量。

A case of extremely poor performance of RDLC report after upgraded to .NET 4.0.


Comments

Be the first to post a comment

Post a comment