带有排序的 MongoDB 范围查询 - 如何加快速度?

Posted

技术标签:

【中文标题】带有排序的 MongoDB 范围查询 - 如何加快速度?【英文标题】:MongoDB range query with a sort - how to speed up? 【发布时间】:2017-10-19 12:22:06 【问题描述】:

我有一个查询通常需要大约 30 秒才能运行一个包含 100 万个文档的集合。此查询将构成搜索引擎的一部分,其中要求每次搜索在 5 秒内完成。在这里使用一个简化的示例(实际文档具有嵌入的文档和其他属性),假设我有以下内容:

100 万个文档,包含 Users 集合,每个集合如下所示:


  name: Dan,
  age: 30,
  followers: 400 
,
 
  name: Sally,
  age: 42,
  followers: 250

... etc

现在,让我想要返回 10 个用户的 ID,这些用户的粉丝数在 200 到 300 之间,按年龄降序排列。这可以通过以下方式实现:

db.users.find(
  'followers':  $gt: 200, $lt: 300  ,
).
projection( '_id': 1 ).
sort( 'age': -1 ).
limit(10)

我创建了以下复合索引,winningPlan 告诉我正在使用它:

db.users.createIndex( 'followed_by': -1, 'age': -1 )

但是这个查询仍然需要大约 30 秒,因为它必须检查数千个文档,在这种情况下几乎等于与 find 查询匹配的文档数量。我已经尝试了不同的索引(具有不同的位置和排序顺序),但没有成功。

所以我的问题是,我还能做些什么来减少使用查询检查的文档数量,或者加快检查文档的过程?

该查询在生产环境和我的本地开发环境中都需要很长时间,在某种程度上控制了许多网络和硬件因素。 currentOp 表示查询在运行时没有等待锁,或者同时有其他查询在运行。

【问题讨论】:

这个托尼运气好吗? 【参考方案1】:

对我来说,您的查询索引似乎不正确: 'followed_by': -1, 'age': -1 。您应该有一个索引 'followers': 1(但要考虑该字段的基数)。但即使使用该索引,您也需要进行 inmem 排序。无论如何,如果您拥有高基数,它应该会更快,因为您不需要像使用索引前缀 followed_by 那样扫描整个集合以进行过滤步骤。

【讨论】:

以上是关于带有排序的 MongoDB 范围查询 - 如何加快速度?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何使用带有 expressjs-nodejs 的 mongoose 对 mongodb 中的 ObjectId 列执行排序?

使用 Spring 数据和 mongoDB 进行日期排序的聚合

如何在带有自定义过滤器的 Spring Data mongodb 中使用分页和排序?

在mongodb中如何给列表按时间排序

MongoDB操作

mongoDB_08索引的操作