linq to sql 系列之 linq to sql性能優化技巧

linq to sql 是一個代碼生成器和ORM工具,他自動爲我們做了很多事情,這很容易讓我們對他的性能產生懷疑。但是也有幾個測試證明顯示在做好優化的情況下,linq to sql的性能可以提升到ado.net datareader性能的93%。

轉自:http://www.cnblogs.com/yukaizhao/archive/2010/05/21/linq-to-sql-10-performance-tips.html


因此我總結了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對象跟蹤服務是完全沒有必要的。

建議將所有的數據庫對象按工作單元分給幾個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>
  publicstatic 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));
        returnfunc;
      }
    }
}

如何使用它呢,請看下面的代碼片段:

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
  {
    returnthis._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做對象跟蹤,請看下面的代碼

1
2
3
4
5
using (NorthwindDataContext context = new NorthwindDataContext())
{
  vara = from c in context.Categories
  selectc;
}

非常簡單,就是一個最基本的linq查詢,讓我們再看下另一個語句

using (NorthwindDataContext context = new NorthwindDataContext())
{
  vara = from c in context.Categories
  selectnew 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查詢優化,需要憂慮性能嗎?

我的微博地址是:http://weibo.com/yukaizhao 我會把一些技術心得碎片寫到微博中,歡迎關注
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章