2010-01-15 37 views
3

任何人都知道爲什麼linq查詢在查詢使用活動記錄vs simplerepository時慢6倍左右? 下面的代碼運行速度比使用簡單存儲庫查詢數據時慢6倍。此代碼是在一個循環中提前使用activerecord的subsonic linq與簡單的資源庫相比非常慢

 string ret = "";    
//  if (plan == null) 
     { 
      plan =VOUCHER_PLAN.SingleOrDefault(x => x.TENDER_TYPE == tenderType); 
     } 
     if (plan == null) 
      throw new InvalidOperationException("voucher type does not exist." + tenderType); 

     seq = plan.VOUCHER_SEQUENCES.First(); 
     int i = seq.CURRENT_NUMBER; 
     seq.CURRENT_NUMBER += seq.STEP; 
     seq.Save(); 
+0

您比較了爲ActiveRecord/SimpleRepository執行的SQL嗎? – 2010-01-17 15:46:17

+0

您是否已經完成了Adam的建議。如果你找到答案,我會很樂意知道。 – Jon 2010-01-21 11:34:16

+0

足夠有趣的配置文件描述了SQL,沒有任何調用需要超過幾個ms。它似乎是應用程序某處的瓶頸:/ – aboutme 2010-01-29 01:46:21

回答

0

我能夠通過緩存它會在構造函數/初始化過程的數據庫實例,以在性能上的巨大差異執行1000次

感謝。現在我看到的是2-3倍的速度,取決於情況和運行。

1)如果只調用默認構造函數,並且具有所有相同的速度優點,那麼只需使用靜態實例替換_db即可正常工作。

// MyProject.MyDB _db; 
// replace with a static instance, and remove the "this." from other lines 
static MyProject.MyDB _db = new MyDB(); 

public MyClass() { 
    //_db=new MyProject.MyDB(); 
    Init(); 
} 

2)我已經寫了一個小緩存類數據庫條目和我打電話說在所有的老地方我ActiveRecord.tt文件,其中「新的()」中使用。

// REPLACE "MyDB" with the name of your DB. Alternately, include this 
// class in Context.tt and have it generate the correct name. 

class ContextDatabaseCache {   

    public static MyDB GetMyDB() 
    { 
     return GetInstance("~~default~~",() => new MyDB()); 
    } 

    public static MyDB GetMyDB(string connectionString) { 
     return GetInstance(connectionString,() => new MyDB(connectionString)); 
    } 

    public static MyDB GetMyDB(string connectionString, string providerName) 
    { 
     return GetInstance(connectionString + providerName,() => new MyDB(connectionString, providerName)); 
    } 

    private static Dictionary<string, MyDB> _dict = new Dictionary<string, MyDB>(); 
    private static MyDB GetInstance(string key, Func<MyDB> createInstance) 
    { 
     if (!_dict.ContainsKey(key)) {    
      lock (_dict) { 
       if (!_dict.ContainsKey(key)) { 
        _dict.Add(key, createInstance()); 
       } 
      } 
     } 
     return _dict[key]; 
    } 

    ///<summary>Call this when the "DefaultConnection" string changes in the 
    ///   App.exe.config file so that a new db instance will be created 
    ///   and pick up the changed value. </summary> 
    public static void Clear() { 
     _dict.Clear(); 
    } 

} 

這是已在ActiveRecord.tt文件進行替換的類型:

public <#=tbl.ClassName#>(){ 
    _db=new <#=Namespace#>.<#=DatabaseName#>DB(); 
    Init();    
} 

    // becomes this: 
public <#=tbl.ClassName#>(){ 
    _db= <#=Namespace#>.ContextDatabaseCache.Get<#=DatabaseName#>DB(); 
    Init();    
} 
-1

這裏一對夫婦的念頭 -

如果你需要做1000次作業,用BatchQuery代替。它將把操作分批到一個操作中,並且相當快速。

我不知道RE Linq是做了什麼 - 但是如果你在最後做了SubmitChanges - 那就是ObjectTracking將會啓動並且它看起來很快。

你在這裏做的優化是一個有趣的 - 一方面它非常有意義(謝謝你的調查) - 另一方面,考慮到你正在嘗試做什麼,你的測試不是最優的。換句話說,我們已經針對這種情況進行了優化 - 您將使用不同的機制:)。

AR和SimpleRepo之間的區別非常簡單--AR有一些代碼可以讓你在開發時更容易一點。 SimpleRepo是光禿禿的骨頭。

有一個使用AR的perf命中 - 這是放大你在這裏做什麼。再說一遍 - 你正在做的不是AR的預期用途。它確實有效,但是如果你在1秒內需要1000次拉/寫 - 你不會得到它。

我們不緩存數據庫的原因是數據庫的東西持有連接信息等。這就是說 - 這是T4,所以你可以做任何需要的:)。

+0

請問您可以發佈一些使用簡單的在線存儲庫的好鏈接。 – 2011-05-11 12:58:52

0

顯然這與亞音速「不是問題」,儘管他們知道它在那裏。它不會被修復。你必須使用糟糕的批量查詢語法來獲得這個,這是沒有人會的。

我不明白的是,這是90%的情況。從表中獲取記錄列表。它應該是快一個,不是慢一個。每個人每時每刻都在做。

亞音速問題如此之多。我必須爲DB字段=>對象字段查找編寫緩存,因爲它們的速度太慢了。

+0

嗨安德魯,你是對的。使用1.0.3時我非常喜歡亞音速。加快發展,加快執行速度。但是當我們將它移植到3.0時,我遇到了很多與速度有關的麻煩。我們現在正在嘗試2.1,因爲我們無法完全改變亞音速。之前,Linq查詢需要兩倍的執行時間。感謝您的數據庫緩存。您能否爲我們提供DB field => Object field lookup的代碼。這將有很大的幫助。 (電子郵件地址已刪除)謝謝 – 2011-05-11 13:52:33

+0

對不起,我回過頭來看看所有的代碼,但我沒有看到亞音速的.TT更改。這是以前的工作,所以我可能不會帶走他們。我認爲它只是遵循正常的「找到它在哪裏,寫一個簡單的基於HashMap的緩存,並完成它」的模式,就像這裏。 – 2011-09-19 05:01:21

2

我們對此進行了一些分析,發現SubSonic的record.SingleOrDefault(x => x.id = someval)比通過CodingHorror完成的相同查詢慢20倍。記錄在這裏:https://github.com/subsonic/SubSonic-3.0/issues/258

探查在ExecutionBuilder.cs指着這個:

// this sucks, but since we don't track true SQL types through the query, and ADO throws exception if you 
// call the wrong accessor, the best we can do is call GetValue and Convert.ChangeType 
Expression value = Expression.Convert(
    Expression.Call(typeof (Convert), "ChangeType", null, 
        Expression.Call(reader, "GetValue", null, Expression.Constant(iOrdinal)), 
        Expression.Constant(TypeHelper.GetNonNullableType(column.Type), typeof(Type)) 
     ), 
    column.Type 
    ); 

令人失望,因爲我真的很喜歡亞音速/ Linq的。

最後我們放棄了,我寫了這個 - http://www.toptensoftware.com/petapoco。移植後,我們的負載測試顯示每秒請求數量增加,CPU負載從大約80%降至5%。

+0

看看這個測試我也做了http://stackoverflow.com/questions/2363735/benchmark-linq2sql-subsonic2-subsonic3-any-other-ideas-to-make-them-faster – Aristos 2011-06-27 23:58:57