程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 挖掘ADO.NET Entity框架的性能

挖掘ADO.NET Entity框架的性能

編輯:關於.NET

ADO.NET團隊最近討論了ADO.NET Entity框架的各種性能特征。ADO.NET Entity框架在12月已經進入它的第三個beta版本,自那時起開發團隊就開始為開發人員提供了使用該框架的相關信息。而現在,則為開發人員提供了框架性能方面的信息。

本文鞭辟入裡地介紹了ADO.NET Entity框架的性能,演示了如何提高簡單查詢速度的方法,並闡釋了框架的性能特征。

需要重點指出的是,當一個抽象層或者類似EDM(譯注:指Entity Data Model)的模塊被用來轉換數據庫的關系樣式時,會帶來一定的性能損失。

查詢與結果

本文使用了NorthWind數據庫作為模型,並創建了一個簡單查詢:

(NorthwindEntities ne = NorthwindEntities())
{
(Order o ne.Orders)
{
i = o.OrderID;
}
}

測試時,我們的每個查詢對整個848行數據進行了10次遍歷。結果很有意思,第1次運行時耗費了4241毫秒,而接下來的每次運行則平均耗費13毫秒左右的時間。最耗時的一部分內容是ObjectContext的創建,而在執行任意一個訪問數據庫的操作時,都會有一些耗時的操作發生。

每次操作的百分比值可以給我們一些啟示:

◆裝載元數據(11%)

◆初始化元數據(14%)

◆打開連接(8%)

◆生成視圖(56%)

◆裝載程序集(2%)

◆跟蹤(1%)

◆實例化(7%)

◆其它(1%)

耗時百分比值最大的是視圖生成,它達到了驚人的56%.既然視圖生成是造成性能損耗的罪魁禍首,那麼開發人員最好是使用命令行工具EDM生成器(EdmGen.exe),運行時需要加上視圖生成命令參數(/mode:ViewGeneration),它的輸出內容為一個代碼文件(C#或者VB.NET),可以包含在項目中。視圖的預生成可以將啟動時間降低到2933毫秒,而對於循環遍歷操作,整個時間可以降低28%.生成視圖並隨著應用程序一起發布是提高性能的妙方,但其缺點則在於視圖不再是動態的,一旦模型發生改變,就需要重新生成以保持同步。

查詢性能

需要指出的是關於性能的主要設計要素是查詢緩存。一旦執行了查詢,它的一部分內容就被維持在全局緩存中。由於查詢與元數據緩存的存在,使得第二次運行的執行速度總是比第一次運行快。例如,如下的Entity SQL查詢:

(PerformanceArticleContext ne = PerformanceArticleContext())
{
ObjectQuery orders = ne.CreateQuery();
(Orders o orders)
{
i = o.OrderID;
}
}

第一次運行該查詢耗時179毫秒,但下一次運行則只耗費了15毫秒的時間。首次運行與後續運行在執行方面的區別在於它構建了能夠為執行傳遞provider的命令樹(command tree)。

LINQ查詢在執行方式上與Entity SQL查詢相似。例如,下面的查詢:

(PerformanceArticleContext ne = PerformanceArticleContext())
{
var orders = from order ne.Orders
select order;
(Orders o orders)
{
i = o.OrderID;
}
}

首次執行LINQ查詢耗時202毫秒,而隨後的執行耗時18毫秒,兩者的差距還要低於Entity SQL.可以看到,使用編譯了的LINQ查詢對於性能的提高更為明顯。編譯LINQ查詢的好處在於它構建了表達樹(expression tree),當查詢被編譯時,後續的執行就不需要重建表達樹了。編譯的LINQ查詢代碼看起來像這樣:

FuncIQueryable> compiledQuery = CompiledQuery.Compile((PerformanceArticleContext ne) =>
(from o ne.Orders select o));
(PerformanceArticleContext ne = PerformanceArticleContext())
{
(Orders o compiledQuery(ne))
{
i = o.OrderID;
}
}

注意,PerformanceArticleContext是一個委托。對於編譯了的LINQ查詢而言,第一次執行耗時305毫秒,而隨後的執行時間則為15毫秒。結果並不驚人,值得關注的是編譯的LINQ查詢比之常規方式的LINQ查詢,執行時間少了3毫秒。或許對於幾個查詢而言,這算不上什麼,但如果有數以千計的查詢,這樣的性能提升就倍顯價值所在了。

ADO.NET團隊建議開發人員在查詢中應謹慎使用Track/NoTrack選項:

在之前的例子中,所有放在對象創建中的查詢結果都被添加到ObjectStateManager中,因此我們能夠跟蹤它們的更新。如果沒有必要跟蹤對象的更新和刪除,那麼最好是使用NoTracking合並項。例如,在一個ASP.NET Web應用程序中,如果它要查詢一個指定的分類名稱,但卻不需要對返回的數據進行更新,那麼NoTracking就會是一個不錯的選擇。在這種情形下,使用NoTracking的查詢會在性能方面得到改善。

基於前面的一組數字,NoTracking選項能夠大幅度地降低執行的時間,而其中性能的提升主要源自於我們停止了對變更的跟蹤以及對關系的管理。如果使用NoTracking查詢,無論是第一次執行還是隨後的執行,編譯的LINQ查詢都要優於標准的LINQ查詢。注意,編譯的LINQ查詢的第二次執行與Entity SQL查詢的第二次執行相等。

ADO.NET團隊同時還提醒開發者在創建查詢時,有一些內容必須銘記於心:

在Entity框架中優化查詢性能時,應該針對特定的編程場景做出最佳選擇。這裡列舉了幾個關鍵項:

◆ObjectContext的首次創建包含了裝載和驗證元數據的性能損耗。

◆任何一個查詢的首次執行都包含了構建一個查詢緩存的性能損耗,以利於提高後續查詢的執行速度。

◆編譯的LINQ查詢比未編譯的LINQ查詢要快。

◆如果不需要跟蹤數據的變更與數據的關系,或者對大數據對象進行流操作,那麼通過NoTracking合並項執行查詢,效果會更佳。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved