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

时间:2017-03-22 15:51:31

标签: mongodb mongodb-query aggregation-framework

我的收藏品有10M文件,并有一个名为movieId的字段;该文件具有以下结构:

{ 
  "_id" : ObjectId("589bed43e3d78e89bfd9b779"), 
  "userId" : 1, 
  "movieId" : 122, 
  "rating" : 5, 
  "timestamp" : 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:
Match performance

更新#2:
" toArray"当VarSize变得越来越大时,帮助我获得了越来越多的价值。没有它我认为返回值只是一个游标。
Match over collection without index

1 个答案:

答案 0 :(得分:0)

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

  1. 你给varSize = 2所以它只需要获取电影ID为0,1,2的文档,所以它需要检查三个索引键并转到db并从db中获取相应的三个文档。这就是你有索引的时候。如果您没有索引,那么它的简单收集扫描会检查所有文档。所以没有索引就是时间。
  2. 案例二 - 你给varSize = 9所以你间接询问所有文件。在索引集合中,它将首先检查所有十个索引条目,然后获取与这10个索引条目对应的所有文档。因此,即使你想要所有文档,它也会转向索引然后获取文档。在非索引环境中,它直接进入集合并将varSize与movie id进行比较并获取doc。因此,这里保存了时间,这会浪费在检查索引条目上。
  3. 注意 - 在案例2中,我采用varSize = 9只是为了更好地解释问题。我想如果varSize = maxMovieId那么即使在索引集合中它也不会使用索引。但是如果varSize有点达到70或80%的值,那么它将尝试使用索引思维它会更快但最终会耗费更多时间。 同样,查询规划器最终会认识到varSize面向maxMovieId的查询需要更多时间,因此即使对于索引集合也不会使用索引。但是,当查询计划程序在后台运行查询并在后台检查时间内部的各种计划时,我们无法判断它何时会发生。

    总结,索引工作"不是很直接"当你做范围查询。也许这就是为什么他们有equality-sort-range rule

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

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

    我现在不了解您的图表,我认为这是错误的,或者您无法清楚地解释它或图表中缺少某些信息。使用10M文档时,橙色线不会花费更少的时间。你能否澄清一下varSize的考虑因素,因为当我们进行范围查询时,范围值很重要。