【问题标题】:Is shortening MongoDB property names worthwhile?缩短 MongoDB 属性名称值得吗?
【发布时间】:2012-09-29 05:49:59
【问题描述】:

Blog rolling with mongoDB, express and Node.js 中,作者提到缩短属性名称是个好主意:

....经常报告的 mongoDB 问题是 磁盘上数据的大小...每条记录都存储所有字段名称 .... 这意味着它通常可以 拥有诸如“t”或“b”之类的属性更节省空间 而不是“标题”或“正文”,但是为了避免混淆,我会避免 除非真的需要!

我知道如何做到这一点的解决方案。我更感兴趣的是什么时候真正需要这样做?

【问题讨论】:

  • 为什么不自动生成具有缩短属性名称的源代码版本和生产版本?推出更新时从源代码创建生产版本?
  • 根据我的阅读,作者似乎提到缩短属性名称不是一个好主意。我想“真正需要”的意思是“我只有 20 个字节的存储空间,所以我必须缩短属性名称以适应”
  • @TheZ 除非有工具可以为 Mongo 自动缩小,否则我看不出如何安全地完成。
  • 投票给SERVER-863 MongoDB 可以为 IMO 带来的最大改进,因为它将对所有用户产生积极影响。不再为长字段名而烦恼,并显着节省存储成本(如果在驱动程序中实施,还可能节省带宽)。一切都在幕后得到照顾。

标签: mongodb database-schema


【解决方案1】:

引用Donald Knuth

过早的优化是万恶之源(或至少大部分 它)在编程中。

不过,构建您的应用程序似乎是最明智、可维护和合乎逻辑的。然后,如果您遇到性能或存储问题,请处理影响最大的问题,直到性能令人满意或收益递减规律意味着没有必要进一步优化。

如果您不确定特定设计决策的影响(例如长属性名称),请创建一个原型来测试各种假设(例如“较短的属性名称会节省很多空间”)。不要期望测试的结果是决定性的,但它可能会教给你你没想到会学到的东西。

【讨论】:

  • 确实有时您可以预见到问题。如果您知道 a) 您的数据库将看到沉重的负载,b) 集合将增长到包含大量记录,并且 c) 字段名称的大小相对于集合中数据的大小而言很大,那么您可以合理地预测问题。考虑一下,如果您发现自己创建大量记录后才遇到此问题,那么 MongoDB 将很难纠正,甚至可能需要任何使用 db 的应用程序停机。
  • 当然,设计过程必须考虑非功能性要求,例如主机环境、可用空间、性能等。应审查设计以确保它可能满足这些要求,测试将表明应用程序是否有效,以及在其投入生产之前很久是否需要采取补救措施(以及采取何种措施)。这不是过早的优化,而是针对需求进行测试。
  • 我只是认为这不是一个好的答案。小优化与大回报的平衡总是获胜。我现在感觉到了,因为我有大键,所以在数据库中拥有大量数据之后,现在优化的成本是巨大的。
  • 我完全同意@Alexandru 的 cmets。您可以教人们每个短名称的含义,但是一旦性能失控,您不能简单地重写代码和更改数据库而无需巨额成本。对于任何软件的用户来说,重要的是性能。软件工程师如何实现它并不重要。
【解决方案2】:

底线:所以要保持紧凑,因为它仍然有意义。

我不认为这是每一个真正需要缩短为一个字母的名字。无论如何,您应该尽可能缩短它们,并且您对此感到满意。假设您有一个用户 name: {FirstName, MiddleName, LastName},您甚至可以使用 name:{first, middle, last}。如果您觉得舒服,您可能会觉得 name:{f, m,l} 没问题。
您应该使用短名称:因为它会消耗磁盘空间、内存,因此可能会在一定程度上减慢您的应用程序(内存中保存的对象更少,由于更大的大小和更长的查询时间导致查找时间更慢,因为查找数据需要更长的时间)。
一个好的模式文档可能会告诉开发人员 t 代表城镇而不是标题。根据您的堆栈,您甚至可以通过一些辅助工具来隐藏开发人员使用这些快捷方式来映射它。

最后我要说的是,对于何时以及缩短多少架构名称没有指导方针。这在很大程度上取决于您的环境和要求。但是,如果您可以提供一个很好的文档来解释所有内容和/或提供实用程序来简化开发人员和管理员的生活,那么您最好保持它的紧凑性。无论如何,管理员可能会直接与 mongodb 交互,所以我想不应该错过一个好的文档。

【讨论】:

    【解决方案3】:

    如果使用详细的 xml,尝试使用自定义名称来改善这一点可能非常重要。 SERVER-863 票证中的用户评论在他的案例中说;我正在使用详细命名存储外部定义的 XML 对象:字段名可能是总记录大小的 70%。因此,在 I/O 和内存效率方面,字段名称标记化可能是一个巨大的胜利。'

    【讨论】:

      【解决方案4】:

      保持有意义名称的优先级高于短名称的优先级,除非您自己的情况和测试提供了更改这些优先级的特定理由。

      SERVER-863comments 中所述,如果您使用 MongoDB 3.0+ 和启用了快速压缩的 WiredTiger 存储选项,长字段名称会变得更少 /em> 的问题,因为压缩有效地为您处理缩短。

      【讨论】:

        【解决方案5】:

        在这上面加上我的 2 美分..

        在设计数据模型时可以避免使用长命名属性(或“AbnormallyLongNameAttributes”)。在我之前的组织中,我们测试了保留简短命名属性的策略,例如,组织定义了 4-5 个字母编码的字符串,例如:

        1. 名字 = FSTNM,
        2. 姓氏 = LSTNM,
        3. 每月利润损失百分比 = MTPCT,
        4. 同比销售预测 = YOYSP,等等..)

        虽然我们观察到查询性能有所提高,但主要是由于通过网络传输的数据大小减少,或者(因为我们将 JAVA 与 MongoDB 一起使用)减少了 MongoDB 文档/Java Map 中“键”的长度堆空间,整体性能提升不到 15%。

        在我个人看来,这是一个微优化,需要额外的成本(也是一个巨大的麻烦)来维护/设计一个额外的系统来管理每个数据模型的数据属性字典。该系统需要在调试应用程序/回答客户查询时具有组织范围内的透明度。

        如果您发现使用此策略将性能提高 20% 对您来说是有利可图的,那么可能是时候扩展您的 MongoDB 服务器/选择其他一些数据建模/查询策略了,或者完全选择不同的数据库。

        【讨论】:

        • 伙计,20% 是巨大的!显然,不是在谈论 100k 记录表。
        【解决方案6】:

        我执行了一个小基准测试,我将 252 行数据从 Excel 上传到两个集合 testShortNames 和 testLongNames,如下所示:

        长名称:

        {
            "_id": ObjectId("6007a81ea42c4818e5408e9c"),
            "countryNameMaster": "Andorra",
            "countryCapitalNameMaster": "Andorra la Vella",
            "areaInSquareKilometers": 468,
            "countryPopulationNumber": NumberInt("77006"),
            "continentAbbreviationCode": "EU",
            "currencyNameMaster": "Euro"
        }
        

        简称:

        {
            "_id": ObjectId("6007a81fa42c4818e5408e9d"),
            "name": "Andorra",
            "capital": "Andorra la Vella",
            "area": 468,
            "pop": NumberInt("77006"),
            "continent": "EU",
            "currency": "Euro"
        }
        

        然后我得到了每个文件的统计数据,保存在磁盘文件中,然后对两个文件进行了“差异”:

        pprint.pprint(db.command("collstats", dbCollectionNameLongNames))
        

        下图显示了两个感兴趣的变量:size 和 storageSize。 我的阅读表明 storageSize 是压缩后使用的磁盘空间量,基本上 size 是未压缩的大小。所以我们看到 storageSize 是相同的。显然,Wired Tiger 引擎很好地压缩了字段名。

        然后我运行一个程序从每个集合中检索所有数据,并检查响应时间。

        即使是亚秒级查询,长名称的查询时间也始终增加了大约 7 倍。当然,将较长的名称从数据库服务器发送到客户端程序需要更长的时间。

        -------LongNames-------
        Server Start DateTime=2021-01-20 08:44:38
        Server End   DateTime=2021-01-20 08:44:39
        StartTimeMs= 606964546  EndTimeM= 606965328
        ElapsedTime MilliSeconds= 782
        -------ShortNames-------
        Server Start DateTime=2021-01-20 08:44:39
        Server End   DateTime=2021-01-20 08:44:39
        StartTimeMs= 606965328  EndTimeM= 606965421
        ElapsedTime MilliSeconds= 93
        

        在 Python 中,我只是执行了以下操作(我实际上必须循环遍历项目以强制读取,否则查询仅返回光标):

        results = dbCollectionLongNames.find(query)
        for result in results:
            pass
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多