上下文:连接到MongoDB 4.0服务器的NodeJs(meteorjs)应用程序
我有一组经常计算的数据,我需要存储时间,然后从我的应用访问特定的一组数据。该集合是一个由12 000个对象组成的数组,最终权重约为3MB(通过仅使用一组数据的Collection上的MongoDB集合统计数据来衡量:大小:3.3 MB;计数:12964)。它与一些计算参数有关。我需要使用查询来检索集合。
我必须在两种数据库结构之间进行选择:
选项1:
一个集合存储具有ID的计算引用(将其命名为ReferenceCollection
),另一个集合包含每个计算的所有12000个对象存储为单个文档,而referenceId指向之前创建的ID。
以下是示意图:
ReferenceCollection :
|--- _id: ObjectId("a")
|--- computation : "my reference"
ResultCollection :
|--- _id: ObjectId("b")
|--- referenceId : ObjectId("a")
|--- fieldResut1 : data
.
.
|--- fieldResut20 : data
要检索该集合,我将使用计算参数在第一个集合中查询referenceId),然后使用参考ID查询第二个集合以获取12000个文档。
let reference = ReferenceCollection.findOne({computation: "my reference"}) // this is lightweight
let results = ResultCollection.find({referenceId: reference._id}) // this search for the 12 000 results
选项2: 单个集合存储计算引用,该集合的键包含一个包含内部数据数组的键
以下是示意图:
ResultCollection :
|--- _id: ObjectId("b")
|--- computation : "my reference"
|--- result : Array(
|--- fieldResut1 : data
.
.
|--- fieldResut20 : data
)
要检索该集合,我将只对自己的计算参数进行一次查询,以获得包含所有数据的单个文档。
问题: 我使用第一个选项遇到性能问题:从MongoDB桌面客户端(studio 3T)查询和检索所有12000文档非常慢:在我的设置中为3秒。第二个选项只需1秒钟即可检索(这些时间包括数据下载)。这导致我的应用在获取数据时需要等待很多时间。
返回游标时,从服务器上的mongoshell查询非常快(选项1大约20ms)。
您能确认选项2是存储此数据的好选择吗?
关于数据结构,我还有其他选择吗?
我在单个节点上运行MongoDB。您是否认为设置副本集可以帮助提高读取性能?
答案 0 :(得分:0)
在这种情况下,您可能会发现差异主要是由于必须执行两个与您的网络最相关的连接/查询。
例如,如果在交易集合中引用了用户集合,则将使用选项1。
这个想法是,如果您需要连接两个集合,则只有在要多次引用连接的集合并且文档复杂的情况下,才可以这样做。
如果只是有一个名称集合,然后在另一个集合中引用它,那就错了。
如果您需要连接两个Mongo集合,请考虑使用聚合,这样与需要执行多个查询相比,Mongo服务器可以一击获得数据。
编辑:
为使您对性能有所了解,目前的第一个选择将花费两倍的时间,纯粹是因为它必须连接两次。如果相同的查询经常发生,那么您确实会发现性能下降毫无益处(除非“ computation”(计算)字段发生了很大的变化,否则可能是合理的)。如果您使用的是聚合,那么您将不会看到任何性能下降,因为它被视为单个连接。
选项二只是一次查找,然后是返回数组数据所需的时间。因此,在大多数情况下,使用聚合时与选项1相同。
如果数组由复杂的对象组成,则也可能会成为瓶颈。理想情况下,您应该避免使用数组并将其展平为带有字段的单个文档。这样,当您执行查询时,您可以设置要返回的字段,从而不返回不需要的字段。