MongoDB匹配索引与无索引-聚合

MongoDB匹配索引与无索引-聚合,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我的收藏有1000万个文档,有一个名为movieId的字段;该文件的结构如下: { “_id”:ObjectId(“589bed43e3d78e89bfd9b779”), “用户ID”:1, “电影ID”:122, “评级”:5, “时间戳”:838985046, “newId”:0.0 } MovieId是一个介于1-7000之间的数字 我有两个版本的这个集合(副本);第一个是movieId的索引: db.collection.createIndex({movieId:1}); 另一

我的收藏有1000万个文档,有一个名为movieId的字段;该文件的结构如下:

{
“_id”:ObjectId(“589bed43e3d78e89bfd9b779”),
“用户ID”:1,
“电影ID”:122,
“评级”:5,
“时间戳”:838985046,
“newId”:0.0
}
  • MovieId是一个介于1-7000之间的数字
  • 我有两个版本的这个集合(副本);第一个是movieId的索引:
db.collection.createIndex({movieId:1});
  • 另一个版本没有此索引
我正在运行以下查询(VarSize只是一个变量):

db.collection.aggregate(
[{
$match:{“movieId”:{$lte:VarSize}
}]);`
我正在比较此查询性能,但是当
VarSize
很少时,使用索引查询集合会更快(1-2秒),而不使用索引查询集合则需要14秒。但当
VarSize
较大,大于1000时,查询索引集合比查询未索引集合慢;查询索引集合的时间要长两倍

更新#1:

更新#2:
“toArray”帮助我在VarSize变得越来越大的同时获得了越来越多的值。如果没有它,我认为返回值只是一个光标

我认为它应该很直。首先,它不是一个覆盖查询,否则您将获得更好的性能。使用索引coll。在这里,您选择的是完整文档,该文档还具有电影id和_id。 坚持基本原则,我将尝试解释DB中可能发生的情况- 考虑DB和电影ID中只有10个文档是序列值(即使它们不是,那么它也可以,但我考虑顺序只是为了理解目的)

  • 您给varSize=2,所以它只需要获取电影id为0、1、2的文档,所以它需要检查三个索引键,然后转到db并从db获取相应的三个文档。这一切都是当你有索引的时候。当您没有索引时,只需对所有文档进行简单的集合扫描即可。因此,如果没有索引,这需要时间
  • 案例二——你给varSize=9,所以你间接询问所有的文档。在索引集合中,它将首先检查所有10个索引项,然后获取与这10个索引项对应的所有文档。所以,即使您需要所有文档,它也会先进行索引,然后获取文档。而在非索引环境中,它直接进入集合,将varSize与电影id进行比较并获取文档。因此,这里节省了检查索引项所浪费的时间
  • 注意——在案例2中,我采用varSize=9只是为了更好地解释这个问题。我认为如果varSize=maxMovieId,那么即使在索引集合中也不会使用索引。但如果varSize的值在70%或80%之前,那么它将尝试使用索引,认为它会更快,但最终会消耗更多的时间。 同样,QueryPlanner最终会认识到,对于varSize朝向maxMovieId的查询,它需要花费更多的时间,所以即使对于索引集合,它也不会使用索引。但我们无法判断什么时候会发生这种情况,因为QueryPlanner在后台运行querues并在后台检查各种计划

    总之,在进行范围查询时,索引工作“不是很直接”。也许这就是为什么他们要这么做

    编辑:我是对的,这是我的测试结果-

    • 我添加了10 M文档,其结构{u id:ObjectID,“a”:1}使用for循环,“a”值随着一个新文档每次增加1。如果没有索引,当我用:$lte查询任何值时,在我的机器上几乎需要相同的时间~650毫秒。即使是$lte=1,也需要相同的时间。所以,当没有索引时,所花费的时间是线性的,因为它必须检查每个文档。如果仔细观察executionStats输出,您会发现只有一个阶段是COLLSCAN。在这个阶段,我们只是检查所有1000万份文档
    • 我在索引{a:1}之后对同一集合执行了相同的解释。结果都是不同的。当a:$lte=10或a:$lte=100时,则所需时间约为47毫秒。但如果我给出a:$lte=1000000,则所需时间为1442毫秒,几乎是无索引时所需时间的2.5倍。我在检查executionStats输出后得到了原因。现在有两个阶段。与单级扫描相比,IXSCAN和FETCH需要花费大量时间

    我现在不明白你们的图表,我认为它是错误的,或者你们不能解释清楚,或者图表中缺少一些信息。Orange line处理1000万份文档所需的时间无法缩短。您能否澄清一下在哪里考虑varSize,因为当我们进行范围查询时,范围值非常重要。

    您的文档只有一个字段
    movieId
    ?关于
    \u id
    字段呢?你能展示你收藏中的一个示例文档,并确认索引是什么吗?@SergeyBerezovskiy是的,有_id字段,但我认为即使有许多其他字段,它对查询的性能也无关紧要。@VinceBowdren文档的结构是:{“\u id”:ObjectId(“589bed43e3d78e89bfd9b779”),“userId”:1,“movieId”:122,“rating”:5,“timestamp”:838985046,“newId”:0.0}现在我有了更多的字段,但它不会改变结果。我用db.collection.createIndex({movieId:1})创建了索引;谢谢你的回答。现在,这是真的,通过索引总是有这个步骤,在某些情况下,它不是最有效的。但是,在这张图中,我显示了我的结果。我认为索引集合结果是正确的。但是没有索引集合在图中永远不会减少。首先,因为它总是要询问所有文档和数据第二个原因是VarSize越大,返回的文档数量越大。我尝试了不同类型的集合,得到了相同的结果。我还看到了检查索引使用情况的统计数据。但是没有索引coll。根据图表,时间在减少。索引col是什么意思