MongoDB千万级子集合下两种父子关系方案的性能咨询
MongoDB 1000万级address集合下,两种父子关联方案的性能对比
方案回顾
方案1:子集合存储父ID关联
users集合文档:
{ "_id": "63e422adcb1ee8e6ffa4f4c7", "name": "Joe" }
address集合文档:
{ "_id": "77775554441ee8e6ffa4f4c7", "parent_id": "63e422adcb1ee8e6ffa4f4c7", // 关联users的_id "street": "123 Fake Street", "city": "Faketon", "state": "MA", "zip": "12345" }, { "_id": "55545adcb1ee8e6ffa4f4c7a", "parent_id": "63e422adcb1ee8e6ffa4f4c7", "street": "123 Fake Street", "city": "Faketon", "state": "MA", "zip": "12345" }
核心逻辑:address通过parent_id字段存储对应users的_id,建立关联。
方案2:父集合存储子ID数组关联
users集合文档:
{ "_id": "63e422adcb1ee8e6ffa4f4c7", "name": "Joe", "address_ids": [ // 存储address的_id数组 "77775554441ee8e6ffa4f4c7", "55545adcb1ee8e6ffa4f4c7a" ] }
address集合文档:
{ "_id": "77775554441ee8e6ffa4f4c7", "street": "123 Fake Street", "city": "Faketon", "state": "MA", "zip": "12345" }, { "_id": "55545adcb1ee8e6ffa4f4c7a", "street": "123 Fake Street", "city": "Faketon", "state": "MA", "zip": "12345" }
核心逻辑:users通过数组字段存储所有关联address的_id,建立关联。
性能对比(针对1000万级address集合)
方案1优势
- 查询效率高:给
address.parent_id建立单键索引后,查询某个用户的所有地址时,MongoDB可以通过索引快速定位目标文档,1000万数据量下单键索引的查询响应时间稳定,性能优异。 - 读写操作低开销:新增/删除地址仅需操作address集合的单个文档,无额外同步开销;并发读写时不会出现热点文档问题,可扩展性强。
- 数据一致性易维护:无需同步更新users集合,避免了因关联数据不同步导致的无效引用问题。
- 无文档大小限制风险:users文档不会随着address数量增加而膨胀,完全规避MongoDB单个文档16MB的大小限制。
方案2劣势
- 查询性能瓶颈:查询用户地址需先从users文档取出ID数组,再用
$in查询address集合。若单个用户地址数量较多,数组长度过大时$in查询性能会显著下降;同时users文档膨胀会增加读取开销。 - 写操作性能差:新增/删除地址需更新users文档的数组字段,并发写请求会导致users文档成为热点,容易产生锁冲突;文档更新时若超出预分配空间,还会触发文档移动,大幅增加IO开销。
- 数据一致性维护成本高:若address文档被删除,需同步更新users数组,否则会出现无效ID引用,手动维护极易出错。
- 文档大小限制风险:单个用户地址数量较多时,users文档可能快速接近甚至超过16MB的大小限制,直接导致写入失败。
结论
在address集合数据量超过1000万的场景下,方案1(子集合存储父ID)的性能远优于方案2,是更适合的关联方案。实际使用时务必给address.parent_id建立单键索引,若需结合其他字段查询,可按需创建复合索引进一步优化性能。
内容的提问来源于stack exchange,提问作者mostafa amin
相关产品推荐
相关产品推荐

