与 simplerepository 相比,使用 activerecord 的 Subsonic linq 速度非常慢

发布于 2024-08-17 21:36:11 字数 578 浏览 4 评论 0原文

有人知道为什么在使用活动记录查询时 linq 查询比使用 simplerepository 查询慢大约 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();

Anyone know anything about why linq queries are about 6 times slower when querying using active record vs simplerepository?
The below code runs 6 times slower than when i query the data using a simple repository. This code is executed 1000 times in a loop

Thanks in advance

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情绪失控 2024-08-24 21:36:11

我们对此进行了一些分析,发现 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
    );

令人失望,因为我真的很喜欢 SubSonic/Linq。

最后我们放弃了,我写了这个 - http://www.toptensoftware.com/petapoco。移植后,我们的负载测试显示每秒请求数上升,CPU 负载从大约 80% 下降到 5%。

We did some profiling on this and found SubSonic's record.SingleOrDefault(x=>x.id=someval) to be up to 20x slower than the same query done through CodingHorror. Logged it here: https://github.com/subsonic/SubSonic-3.0/issues/258.

The profiler pointed at this in 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
    );

Disappointing because I really like SubSonic/Linq.

In the end we gave up and I wrote this - http://www.toptensoftware.com/petapoco. After porting, our load test showed requests per second went up and CPU load dropped from about 80% to 5%.

早茶月光 2024-08-24 21:36:11

通过缓存在构造函数/init 过程中创建的数据库实例,我能够在性能上产生巨大的差异。我现在看到的速度大约是 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) 我为数据库条目编写了一个小缓存类,并在所有使用“new()”的旧位置从我的 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();            
}

I was able to make a HUGE difference in performance by caching the database instance it creates in the constructor/init procedures. What I am seeing now is ~2-3x speed up, depending on the situation and the run.

1) The method of just replacing _db with a static instance works fine if you only call the default constructor, and has all the same speed benefits.

// 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) I have written a little caching class for the DB entries and am calling that from my ActiveRecord.tt file in all the old places where "new()" was used.

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

}

This is the type of replacement that was made in the ActiveRecord.tt file:

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

    // becomes this: 
public <#=tbl.ClassName#>(){
    _db= <#=Namespace#>.ContextDatabaseCache.Get<#=DatabaseName#>DB();
    Init();            
}
执妄 2024-08-24 21:36:11

显然,这对于亚音速来说“不是问题”,尽管他们知道它的存在。它不会被修复。你必须使用蹩脚的批处理查询语法才能得到这个,但没有人会这么做。

我不明白的是,90%的情况都是如此。从表中获取记录列表。它应该是快的,而不是慢的。每个人、任何地方、任何时候都这样做。

亚音速的问题很多。我必须为数据库字段编写缓存=>对象字段查找,因为它们也太慢了。

Apparently this "isn't an issue" with subsonic, though they know it is there. It will NOT be fixed. You have to use a crappy batch query syntax to get this, which no one will.

The thing I don't understand about that is that this is the 90% case. Get a list of records from a table. It should BE the fast one, not the slow one. Everyone does it, everywhere, all the time.

So many problems with subsonic. I had to write caching for the DB field => object field lookups, since they were so damn slow too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文