MongoDB Document Best Practices: Avoid Common Pitfalls with Real‑World Cases
This article outlines essential MongoDB document best‑practice guidelines, including key naming restrictions, collection organization, avoiding custom _id values, pitfalls of array fields, compression of large fields, using MD5 hashes for long strings, case‑sensitivity handling, and index size limits, illustrated with real‑world cases.
In the previous article we introduced MongoDB databases and collections; this piece focuses on practical considerations and online examples for the "document" data type.
Document
Document keys must not contain any special characters other than the underscore.
Store documents of the same type in a single collection and separate different types into different collections.
Uniform document types greatly improve index utilization; mixing types can cause frequent full‑collection scans.
Avoid using custom values for _id .
【案例3】某业务的MongoDB在放量后出现严重的写入性能问题,大致为:写入达到300/s的时候IO跑满,排查中发现,该业务在设计的时候为了方便, 而将_id中写入了无序的类似md5的数据。MongoDB的表与InnoDB相似,都是索引组织表,数据内容跟在主键后,而_id是MongoDB中的默认主键,一旦_id的值为非自增,当数据量达到一定程度之后,每一次写入都可能导致主键的二叉树大幅度调整,这将是一个代价极大的写入, 所以写入就会随着数据量的增大而下降,所以一定不要在_id中写入自定义的内容。Avoid using array fields as query conditions.
【案例4】某业务在一个表的数组字段上创建了一个索引,创建完毕之后发现表体积增大了很多很多,排查发现是由于索引体积的大幅度增大导致在MongoDB中,如果为一个数组字段添加索引,那么MongoDB会主动为这个数组中的所有元素依次添加独立索引,例如: 为数组字段{a:[x,y,z]}添加索引{a:1},实际上添加的索引为:{a:[x:1]} {a:[y:1]} {a:[z:1]} 该业务的数组字段中有11个元素,那么等于一次创建了11条索引,这是索引体积大幅度增大的根本原因。 另外,如果组合索引中存在数组字段,那么MongoDB会为每一个元素与其它字段的组合创建一个独立的索引,例如: 为数组字段{a:[x,y,z]}和{b:qqq}添加索引{a:1,b:1},实际上添加的索引为: {a:[x:1],b:1} {a:[y:1],b:1} {a:[z:1],b:1} 如果一个组合索引中存在两个数组字段,那么索引的数量将是两个数组字段中元素的笛卡儿积,所以MongoDB不允许索引中存在一个以上的数组字段。
If a field is large, store it compressed.
【案例5】某业务上线后一直很正常,但在放量3倍之后发现MongoDB服务器的网卡流量报警,IO压力报警,排查中发现,该业务讲一个超长的文本字段存 放在MongoDB中,而这个字段的平均体积达到了7K。在并发为2000QPS的场景下,每次取出1~20条数据,导致这个MongoDB每秒钟要发送将 近100MB的数据,而对于数据库而言,读写均为随机IO,所以在如此大的数据吞吐场景中,IO达到了报警阈值。由于文本是一个容易压缩的样本, 所以我们对该字段进行了压缩存放,使其平均体积降低到了2K,而解压在业务端进行处理,最终将吞吐降低到了20MB/S左右。
If a large field is used as a query condition (e.g., a long URL), store its MD5 hash instead.
【案例6】某业务上线前进行压力测试,测试中发现某个场景下的查询性能不够理想,排查中发现该场景的查询条件类似:{url:xxxx},而url字段中的值大部分都很长很长,该字段的平均体积达到了0.5K,在这种情况下索引的体积会变得很大从而导致虽然请求虽然能够走索引但效率并不够理想,于是dba配合业务开发一起对该场景进行优化: 1.将该字段的存放的内容由真实的url改为url内容md5后的值,字段体积得到了大幅度缩小,固定在了32位 2.查询时,用户请求通过url查询,而此时程序会将该url进行md5,然后用得到的值进行查询,由于所以体积大幅度缩小,所以查询速度有了极大的提高,优化完毕后再次进行压力测试,性能达标,为之前的6倍。MongoDB is case‑sensitive; if case sensitivity is not required, store data in a uniform case or add a normalized auxiliary field.
【案例7】 某业务需要根据字段{a:XxX}来进行查询,在MongoDB中a的值是大小写敏感的,并且无法配置为忽略大小写,但该业务场景为了满足查询需求而需要忽略大小写,这个大小写敏感与否的矛盾导致业务需要使用正则来进行匹配:{a:/xxx/i},i参数在正则中表示忽略大小写,上线后发现, 查询性能非常低下,在一个拥有200万文档的集合中一次查询需要消耗2.8~7秒,并发达到50QPS的时候MongoDB实例所在服务器的CPU就跑到了973%。MongoDB在查询条件中使用正则的时候,能够像普通精确匹配一样使用索引达到高效率的查询,但一旦使用了参数i来忽略大小写查询优化器就需要对每一个数据的大小写进行调整然后再进行匹配,此时这个请求就变成了全表扫描,这就是效率低下的根本原因。 对于这种场景可以采用新建一个统一了大小的字段,例如全部小写:假设原字段为:{a:aAbB},那么为其添加一个全部为小写的对应字段:{a_low:aabb}然后通过字段a_low进行查询就能达到精确匹配,按照该方案改进后,该场景的查询耗时降低到了2毫秒 虽然新增字段导致实例会变大一些,但对于换来性能的大幅度提升还是非常值得的。
Do not store strings longer than 1 KB if they are used as query conditions; MongoDB indexes support only fields up to 1 KB.
MongoDB的索引仅支持1K以内的字段,如果你存入的数据长度超过1K,那么它将无法被索引。
Hope the above content helps everyone; the next article will cover index‑related topics.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
360 Zhihui Cloud Developer
360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
