ServiceStack基准测试仍在继续:为什么将简单(复杂)的数据持久化为JSON会减慢SELECT的速度?

时间:2018-06-28 12:39:57

标签: c# servicestack ormlite-servicestack

因此,myzz不喜欢我在上一个SO问题中没有如此科学的基准问题,但是由于我想切换到OrmLite,因此我需要弄清楚它是否慢,如果慢,为什么。 / p>

在我的“研究”中,我得出一个结论:在OrmLite中,复杂对象被blob到JSON,这是非常慢的SELECTs的元凶。

因此,我创建了一个仅专注于OrmLite的新项目,并且不与其他项目进行比较,这里的目的是了解拥有JSON对象和不拥有JSON对象之间的区别。

可以在GitHub上找到它: https://github.com/tedekeroth/ormlitebenchmarking 解决方案如下所示:
enter image description here

  

我正在Windows 7、2.6Ghz,24 GB RAM和Windows 7上运行OrmLite 5.1.1   当前的CPU负载,使用MySql 5.6。应用程序连接到   127.0.0.1(root / root),并且需要数据库“ ormlite”。

我已启用ThrowOnError:

OrmLiteConfig.ThrowOnError = JsConfig.ThrowOnError = true;

该应用程序如下所示:

enter image description here

  • 无数据:仅创建对象,无属性具有数据 enter image description here
  • 原语:仅填充一些简单的原始属性 enter image description here
  • 罪恶+一个复杂的对象:上述所有基元+一个模糊的复杂对象 enter image description here
  • 完整数据:以上所有内容+另外2个复杂的斑点对象 enter image description here

创建按钮首先在列表中创建1万个对象,然后使用OrmLite插入方法将其保留。时间测量仅针对INSERT执行,而不创建对象。

public void AddRow<T>(T coreObject) where T : CoreObject
{
    long id = 0;
    using (var _db = _dbFactory.Open())
    {
        id = _db.Insert<T>(coreObject, selectIdentity: true);
    }           
}

读取按钮读取表中的所有行,并重新创建Customer对象:

public List<T> FetchAll<T>()
{
    using (var _db = _dbFactory.Open())
    {
        List<T> list = _db.Select<T>();
        return list;
    }
}

因此,测试应像这样进行:

  • 选择模式,然后按创建,将显示花费的时间
  • 读取即可读取表中当前所有的行

要测试另一种模式,请清空db表(customer)以使其干净。


Benchmarking

INSERT
创建1万个对象(未测量)并将其插入数据库。

  • 无数据:〜26-27秒
    enter image description here
  • 原语:〜27.1-27.4秒
    enter image description here
  • 罪恶+一种复合体:〜27.5-29秒
    enter image description here
  • 完整数据:〜28秒
    enter image description here

所以,总共大约26-29秒。

SELECT
如上所示,从db读取1万个对象。

  • 无数据:〜460毫秒
    enter image description here
  • 原语:〜700-720毫秒
    enter image description here
  • 犯罪+一种复合物:〜970-1030毫秒
    enter image description here
  • 完整数据:30000-32000毫秒(30-32秒)
    enter image description here

结论

“完整数据”显然是出现大量面部表情的地方。 添加的复杂斑点对象(ContactDetails)似乎搞砸了。我在之前的测试中注意到了这一点,但是对象本身并不十分复杂,请参见下文。因此,我不确定为什么会这样跳,或者这些数字是否合理。

这就是为什么我也许Mythz可以看看这个更清洁的基准? =)

问题是:为什么持久化对象(按照OrmLite到JSON)会以这种方式减慢SELECT的速度?

[Serializable]
public class ContactDetails 
{
    public List<ContactItem> ContactItemList
    {
        get; set;
    }
    public ContactItem CurrentContactItem
    {
        get; set; 
    }
    public ContactItem DefaultContactItem
    {
        get; set;
    }
    public bool IgnorePrimaryWaitBuffer
    {
        get; set;
    }

    public ContactDetails(List<ContactItem> contactItemList, ContactItem currentContactItem, ContactItem defaultContactItem)
    {
        ContactItemList = contactItemList;
        CurrentContactItem = currentContactItem;
        DefaultContactItem = defaultContactItem;
    }

    public ContactDetails()
    {
    }
}

1 个答案:

答案 0 :(得分:1)

我设法下载并介绍了此解决方案,该解决方案着重指出了不缓存后期绑定类型的类型访问器的问题的原因,该问题已由this commit解决。

通过这种更改,加载10000行复杂类型的性能从11,765ms减少到 669ms (在我的iMac 5k上),如下所示:

enter image description here

此更改可从v5.1.1(现在为available on MyGet)中获得。

注意:我已删除下面的JsConfig.IncludeTypeInfo行:

JsConfig.IncludeTypeInfo = true;

这会强制序列化程序为increases the payload size and decreases performance的每个对象发出类型信息。 ServiceStack.Text在需要时已经发出类型信息,即对于objectinterfacesabstract类,因此除非绝对需要,否则您很少应该自己强制使用它,因为它可以对性能的重大不利影响。

理想情况下,您的DTO不应使用接口,后期绑定的对象或继承,但如果您考虑使基本类型abstract强制类型信息只在需要的地方使用,而不是总是发出它们。