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

标签 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:
当 VarSize 变大时,“toArray”帮助我获得不断增加的值。如果没有它,我认为返回值只是一个游标。
Match over collection without index

最佳答案

我认为这应该是很直接的。首先,它不是一个覆盖查询,否则你会得到更好的性能。带有索引的col。在这里,您选择包含电影 id 和 _id 的完整文档。 坚持基础知识,我将尝试解释数据库中可能发生的情况 - 考虑数据库中只有 10 个文档,电影 id 是顺序值(即使它们不是,也没关系,但我考虑顺序只是为了理解目的)

  1. 您指定 varSize = 2,因此它需要仅获取电影 id 为 0、1、2 的文档,因此它需要检查三个索引键并转到数据库并从数据库获取相应的三个文档。这一切都是当你有索引的时候。当您没有索引时,只需简单的集合扫描即可检查所有文档。因此,如果没有索引,就需要时间。
  2. 情况二 - 您给出 varSize=9,因此您间接询问所有文档。在索引集合中,它将首先检查所有 10 个索引条目,然后获取与这 10 个索引条目对应的所有文档。因此,即使您想要所有文档,它也会转到索引,然后获取文档。在非索引环境中,它直接进入集合并将 varSize 与电影 id 进行比较并获取文档。因此,这里节省了时间,而这些时间被浪费在检查索引条目上。

注意 - 在案例 2 中,我采用 varSize =9 只是为了更好地解释问题。我认为如果 varSize = maxMovieId 那么即使在索引集合中它也不会使用索引。但如果 varSize 达到 70 或 80% 的值,那么它将尝试使用索引,认为它会更快,但最终会消耗更多时间。 同样,查询规划器最终将认识到,对于 varSize 接近 maxMovieId 的查询需要更多时间,因此即使对于索引集合,它也不会使用索引。但我们无法判断它何时会发生,因为查询规划器在后台运行队列并在幕后定时内部检查各种计划。

总结一下,当您进行范围查询时,索引工作“不是很直接”。也许这就是为什么他们有 equality-sort-range rule .

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

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

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

关于MongoDB 匹配索引与无索引 - 聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42956680/

相关文章:

node.js - SQL 'UNION ALL' 类似 MongoDB 中的实现

node.js - 在默认模式下使用自定义函数?

mongodb - 选择mongoDB聚合中group后的所有字段

python - 如何自定义mongo查询比较规则

node.js - 如何匹配包含和不包含空格的两个字符串

node.js - 通过数组聚合对文档进行评分

node.js - Passport.js - 获取用户 ID 然后查询 mongoDB

mongodb - 不存在的服务 "fos_user.doctrine_registry"

mongodb - Mongodb 中的 Scons

mongodb - 是否可以在聚合框架 mongo 中按投影顺序获取字段