Дозвуковой linq с использованием activerecord очень медленный по сравнению с простым репозиторием - PullRequest
3 голосов
/ 15 января 2010

Кто-нибудь знает что-нибудь о том, почему запросы linq примерно в 6 раз медленнее при запросах с использованием активной записи против простого репозитория? Приведенный ниже код работает в 6 раз медленнее, чем когда я запрашиваю данные с помощью простого репозитория. Этот код выполняется 1000 раз в цикле

Заранее спасибо

        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();

Ответы [ 3 ]

2 голосов
/ 22 марта 2011

Мы провели некоторое профилирование и обнаружили, что запись SubSonic.SingleOrDefault (x => x.id = someval) будет в 20 раз медленнее, чем тот же запрос, выполняемый через CodingHorror. Зарегистрируйся здесь: 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
    );

Разочаровывает, потому что мне действительно нравятся SubSonic / Linq.

В итоге мы сдались, и я написал это - http://www.toptensoftware.com/petapoco. После портирования наш нагрузочный тест показал, что количество запросов в секунду возросло, а загрузка ЦП снизилась с 80% до 5%.

0 голосов
/ 15 июля 2010

Очевидно, что это не проблема с дозвуком, хотя они знают, что это там. Это НЕ будет исправлено. Вы должны использовать паршивый синтаксис пакетного запроса, чтобы получить это, чего никто не будет.

Что я не понимаю, так это то, что это 90% случаев. Получить список записей из таблицы. Он должен BE быстрый, а не медленный. Все делают это везде, всегда.

Столько проблем с дозвуком. Мне пришлось написать кеширование для поиска в поле БД => объектное поле, так как они были слишком медленными.

0 голосов
/ 28 мая 2010

Мне удалось ОГРОМНО изменить производительность, кэшировав экземпляр базы данных, который он создает в процедурах конструктора / инициализации. То, что я вижу сейчас, это ~ 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 во всех старых местах, где использовался «new ()».

// 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();            
}
...