linq to sql 是一個代碼產生器和ORM工具,他自動為我們做了很多事情,這很容易讓我們對他的效能產生懷疑。但是也有幾個測試證明顯示在做好最佳化的情況下,linq to sql的效能可以提升到ado.net datareader效能的93%。
因此我總結了linq to sql的10個效能提升點,來最佳化其查詢和修改的效能。
1. 不需要時要關閉 DataContext的ObjectTrackingEnabled 屬性
using (NorthwindDataContext context = new NorthwindDataContext()){ context.ObjectTrackingEnabled = false;}
關閉這個屬性會使linq to sql停止對對象的標識管理和變化跟蹤。但值得注意的是關閉ObjectTrackingEnabled 意味著也將DeferredLoadingEnabled屬性設定為false,當訪問相關表時會返回null。
2. 不要把所有的資料對象都拖到一個DataContext中
一個DataContext代表一個工作單元,並非整個資料庫。如果幾個資料庫物件之間沒有關係,或者在程式中用不到的資料庫物件(例如日誌表,大量操作表等等),讓這些對象消耗記憶體空間和DataContext對象Tracing Service是完全沒有必要的。
建議將所有的資料庫物件按工作單元分給幾個DataContext來處理。你也可以通過建構函式配置這些DataContext使用相同的資料庫連接,這樣也可以發揮據庫串連池的用途。
3. CompiledQuery --- 有必要就得用
在建立一個linq to sql運算式並將它轉換成對應的sql語句執行的過程,需要幾個關鍵的步驟
1) 建立運算式樹狀架構
2) 轉換成sql
3) 運行sql語句
4) 取回資料
5) 將資料轉換成對象
很顯然,當我們一遍又一遍的執行相同的查詢時,上面1),2)兩個步驟重複執行是在浪費時間。使用System.Data.Linq命名空間下的CompiledQuery類的Compile方法可以避免這種浪費。
請看下面的使用樣本:
Func<NorthwindDataContext, IEnumerable<Category>> func = CompiledQuery.Compile<NorthwindDataContext, IEnumerable<Category>> ((NorthwindDataContext context) => context.Categories. Where<Category>(cat => cat.Products.Count > 5));
func變數現在是一個已經編譯後的查詢,他只需要在第一次運行時編譯一次,就可以重複使用,現在我們將其儲存到一個靜態類中,如下所示:
/// <summary>/// Utility class to store compiled queries/// </summary>public static class QueriesUtility{ /// <summary> /// Gets the query that returns categories with more than five products. /// </summary> /// <value>The query containing categories with more than five products.</value> public static Func<NorthwindDataContext, IEnumerable<Category>> GetCategoriesWithMoreThanFiveProducts { get { Func<NorthwindDataContext, IEnumerable<Category>> func = CompiledQuery.Compile<NorthwindDataContext, IEnumerable<Category>> ((NorthwindDataContext context) => context.Categories. Where<Category>(cat => cat.Products.Count > 5)); return func; } }}
如何使用它呢,請看下面的程式碼片段:
using (NorthwindDataContext context = new NorthwindDataContext()){ QueriesUtility.GetCategoriesWithMoreThanFiveProducts(context);}
4. 使用DataLoadOptions.AssociateWith設定僅從資料庫中取需要的資料
請參考:http://www.cnblogs.com/yukaizhao/archive/2010/05/17/linq_to_sql_DeferredLoadingEnabled_dataloadoption_loadwith_associatewith.html
5. 僅在需要時開啟積極並發控制,換句話說如果不需要請將列的UpdateCheck屬性設定為UpdateCheck.Never,這樣在更新和刪除時可以減少不必要的條件判斷
[Column(Storage=“_Description”, DbType=“NText”, UpdateCheck=UpdateCheck.Never)]public string Description{ get { return this._Description; } set { if ((this._Description != value)) { this.OnDescriptionChanging(value); this.SendPropertyChanging(); this._Description = value; this.SendPropertyChanged(“Description”); this.OnDescriptionChanged(); } }}
可以參考:http://www.cnblogs.com/yukaizhao/archive/2010/05/13/linq_to_sql_1.html 這篇文章中的第三點。
6. 經常設定DataContext.Log查看linq to sql執行時使用的sql,分析取回的資料是否剛好夠用。
using (NorthwindDataContext context = new NorthwindDataContext()){ context.Log = Console.Out;}
7. 僅在有必要時使用Attach方法。
在linq to sql中對象附加是一個的非常好用的機制,但是什麼事情都不是免費的。當在DataContext中Attach對象時,就意味著過一段時間你會使用這個對象,DataContext會給這個對象做“馬上要做修改的”標記。
但是有時候Attach並非必要,例如使用AttachAll去附加一個集合,這個集合中的元素並非都會發生變化。
8. 注意實體標識管理的開銷
在一個非唯讀DataContext中,對象一直會被跟蹤,因此要知道在非直覺的情況下也可能會導致DataContext做對象跟蹤,請看下面的代碼
using (NorthwindDataContext context = new NorthwindDataContext()){ var a = from c in context.Categories select c;}
非常簡單,就是一個最基本的linq查詢,讓我們再看下另一個語句
using (NorthwindDataContext context = new NorthwindDataContext()){ var a = from c in context.Categories select new Category { CategoryID = c.CategoryID, CategoryName = c.CategoryName, Description = c.Description };}
這兩種寫法哪一種更快呢,事實證明第二個語句比第一個要快得多http://blogs.msdn.com/ricom/archive/2007/06/29/dlinq-linq-to-sql-performance-part-3.aspx
為什麼呢? 因為在第一個查詢中查詢出的每一個對象都需要儲存在DataContext中,並對他們做可能會發生變化的跟蹤,而在第二個查詢中你生命了一個新的對象,就不需要再做跟蹤了,所以第二個語句效率會高一些。
9. Linq to sql 提供了Take和Skip方法,使用他們來取需要的記錄,不要把整個表中的記錄都取下來
10. 不要濫用CompiledQuery 方法,如果你確認某個查詢只會執行一遍,那就不要使用CompiledQuery來了,使用它也是需要付出代價的。
最後希望這些技巧對你有用。歡迎發表評論。
本文是翻譯文章;
原文請看 http://www.sidarok.com/web/blog/content/2008/05/02/10-tips-to-improve-your-linq-to-sql-application-performance.html
linq to sql相關隨筆:
1. 從CUD開始,如何使用LINQ to SQL插入、修改、刪除資料
2. 查詢 使用LINQ to SQL做簡單查詢
3. 查詢 消極式載入與立即載入,使用LoadWith和AssociateWith
4. 查詢 inner join,left outer join
5. Linq to SQL中的彙總grouping having
6. LINQ to SQL查詢最佳化,需要憂慮效能嗎?