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

2024-01-17

我想切换到 OrmLite,我需要弄清楚它是否很慢,如果是,原因是什么。

在我的研究中,我得出的结论是,复杂的对象(在 OrmLite 中被 blob 为 JSON)是 SELECT 速度非常慢的罪魁祸首。

因此,我创建了一个仅关注 OrmLite 的新项目,不与除自身之外的任何其他项目进行比较,这里的目的是了解具有 blob 的 JSON 对象与不具有它们之间的差异。

可以在 GitHub 上找到:https://github.com/tedekeroth/ormlitebenchmarking https://github.com/tedekeroth/ormlitebenchmarking

解决方案如下所示:

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

我已启用 ThrowOnError:

OrmLiteConfig.ThrowOnError = JsConfig.ThrowOnError = true;

该应用程序如下所示:

没有数据:只有创建的对象,没有属性有数据:

基元:仅填充一些简单的基元属性:

Prim + 一个复杂对象:上述所有基元 + 一个 blobed 复杂对象:

完整数据:以上所有内容 + 另外 2 个复杂的 blob 对象:

The Create按钮首先在列表中创建 10 000 个对象,然后使用 OrmLite Insert 方法将它们持久化。时间测量仅针对 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);
    }           
}

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

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

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

  • 选择模式,然后按Create, 将显示花费的时间
  • Press Read读回表中当前的所有行

要测试另一种模式,请清空数据库表(customer)有一个干净的。


基准测试

INSERT
创建 10 000 个对象(未测量)并将它们插入数据库。

  • No data: ~26-27 seconds
    enter image description here
  • Primitives: ~27.1-27.4 seconds
    enter image description here
  • Prim + one complex: ~27.5-29 seconds
    enter image description here
  • Full data: ~28 seconds
    enter image description here

所以,总而言之,大约相同,26-29 秒。

SELECT
从数据库读取 10 000 个对象,如上面插入的。

  • No data: ~460 ms
    enter image description here
  • Primitives: ~700-720 ms
    enter image description here
  • Prim + one complex: ~970-1030 ms
    enter image description here
  • Full data: 30000-32000 ms (30-32 seconds)
    enter image description here

结论

“完整数据”显然是最大的打击出现的地方。 添加的复杂 blob 对象 (ContactDetails),似乎把事情搞砸了。我在之前的测试中注意到了这一点,但该对象本身并不是很复杂,请参见下文。所以,我不确定为什么会这样跳,或者这些数字是否合理。

我之前曾就此问题提出过问题,但这个基准测试应该更准确。

问题是:为什么持久化对象(按照 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()
    {
    }
}

我已成功下载并分析了此解决方案,该解决方案突出显示了未缓存后期绑定类型的类型访问器问题的原因,该问题已通过以下方法解决这次提交 https://github.com/ServiceStack/ServiceStack.Text/commit/2404683865ccefdb68a6d18bbc04b9ca368fec92.

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

此更改从 v5.1.1 开始可用可在 MyGet 上找到 http://docs.servicestack.net/myget.

注意:我已经删除了JsConfig.IncludeTypeInfo下面一行:

JsConfig.IncludeTypeInfo = true;

这迫使序列化器为每个对象发出类型信息增加有效负载大小并降低性能 https://stackoverflow.com/a/10759250/85785。 ServiceStack.Text 将在需要时发出类型信息,即object, interfaces and abstract类,因此除非绝对需要,否则您应该很少强迫自己这样做,因为它可能会对性能产生重大不利影响。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ServiceStack 基准测试继续:为什么将简单(复杂)持久化为 JSON 会减慢 SELECT 速度? 的相关文章

随机推荐