降低 RavenDB 中的解析成本

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 54w+ 字,讲解图 2476+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 1900+ 小伙伴加入学习 ,欢迎点击围观

请注意,这是我们正在为 4.0 考虑的事情。

RavenDB 原生使用 JSON 来处理几乎所有的事情。这对 JSON 文档数据库有意义。 JSON 易于解析、人类可读,并且在大多数情况下,没有真正的复杂性。

然而,虽然 JSON 易于解析,但解析它会产生一些计算开销。事实上,在我们的性能测试中,我们花了很多时间来序列化和反序列化 JSON。这是我们必须处理的主要成本之一,主要是因为这是经常发生的事情。我们以前使用 BSON 在内部存储文档,但分析实际上表明,将数据保存为 JSON 文本并对其进行解析的成本更低。这就是我们目前正在做的事情。

然而,更快的解析仍然是解析,这是我们想要避免的。这在内存中的实际表示方式也存在问题。让我们考虑以下 JSON:


 {"FirstName":"John","LastName":"Smith"}

在内存中,这表示为(高度简化):

  • Dictionary<string,object> 实例
  • 键的字符串[]
  • “名字”字符串
  • “姓氏”字符串
  • object[] 的值
    • “约翰”字符串
    • “史密斯”字符串

    换句话说,特别是对于大文档,有 很多 正在创建的小对象。这不会影响即时解析成本,但确实需要在事后收集这些成本,这 我们希望避免的事情。

    我们目前正在考虑使用 Flat Buffers 进行内部文档存储。 Flat Buffers 的好处是没有中间解析步骤。您将获得一块可以立即访问的内存。这有两个主要优点,将文档加载到内存意味着只需从磁盘读取缓冲区,无需额外成本。但这也意味着释放文档的行为会便宜得多,我们只需要再次收集缓冲区,而不是潜在的数万个小对象。

    另一个好处是我们通常需要加载要索引的文档,而通常索引只需要文档中很少的字段。通过避免解析成本,只为我们实际接触的对象付出代价,我们可以更好地降低索引成本。

    使用平面缓冲区的粗略模式是:

    
     {"FirstName":"John","LastName":"Smith"}
    

    文档中的值按字段名称排序,因此我们可以使用二进制搜索来搜索字段。

    Nitpicker 角落:是的,我们可能想在这里使用哈希,但这是一个粗略的草稿来测试东西,稍后会出现。

    我们需要优化模式,使用它 不会 很有趣,但速度和内存的改进应该是显着的。

    另一种选择是这样的模式:

    
     {"FirstName":"John","LastName":"Smith"}
    

    这里我们将所有字段名称存储一次,然后我们使用其在根对象中的索引来引用字段名称。这应该具有减少重复字符串名称的优点。