6

假设我有一个看起来像这样的查询:

db.things.find({
  deleted: false,
  type: 'thing',
  $or: [{
    'creator._id': someid
  }, {
    'parent._id': someid
  }, {
    'somerelation._id': someid
  }]
}).sort({
  'date.created': -1
})

也就是说,我想找到满足这三个条件之一的文档并按最新排序。但是,$or 查询在与排序一起使用时不会并行使用索引。因此,我将如何索引这个查询?

http://docs.mongodb.org/manual/core/indexes/#index-behaviors-and-limitations

您可以假设以下选择性:

  • deleted- 99%
  • type- 25%
  • creator._id, parent._id, somerelation._id- < 1%
4

4 回答 4

5

现在您将需要多个索引来执行此查询;毫无疑问。

问题是什么索引

现在您必须考虑到,由于 MongoDB 查询优化器中的错误,您的任何人都无法使用索引以最佳方式对数据进行基本排序: https$or ://jira.mongodb.org/browse/SERVER- 1205 .

所以你知道$or排序会有一些性能问题,并且将排序字段放入$or子句索引是无用的atm。

因此,考虑到这一点,您想要的第一个索引是涵盖您正在执行的基本查询的索引。正如@Leonid 所说,您可以将其制成复合索引,但是,我不会按照他的顺序进行操作。相反,我会这样做:

db.col.ensureIndex({type:-1,deleted:-1,date.created:-1})

deleted由于其超低的选择性,我完全不确定该字段是否在索引中;事实上,它可以在索引中而不是被取出来创建一个性能较低的操作(对于大多数数据库,包括 SQL 来说都是如此)。这部分需要您进行测试;也许该字段应该是最后一个(?)。

至于索引的顺序,我也只是猜到了。我已经对所有字段说了 DESC,因为您的排序是 DESC,但是您需要explain自己在这里进行。

这样应该能够处理查询的主子句。现在来处理那些$ors。

每个都$or将单独使用一个索引,MongoDB 查询优化器也会为它们单独查找索引,就好像它们完全是单独的查询一样,所以这里值得注意的是关于复合索引的一些问题(http://docs.mongodb.org /manual/core/indexes/#compound-indexes)是它们在前缀上工作(这里的示例注释:http: //docs.mongodb.org/manual/core/indexes/#id5)所以你不能做一个单个复合索引覆盖所有三个子句,因此在$or(考虑到上面的错误)上声明索引的更优化方法是:

db.col.ensureindex({creator._id:1});
db.col.ensureindex({aprent._id:1});
db.col.ensureindex({somrelation._id:1});

它应该能够让您开始为您的查询创建最佳索引。

但是,我应该强调,您需要自己进行测试。

于 2013-02-13T18:47:15.580 回答
3

Mongodb 每次查询只能使用一个索引,所以我看不到someid在您的模型中使用索引进行查询的方法。

因此,最好的方法是为此任务添加特殊字段:

ids = [creator._id, parent._id, somerelation._id]

在这种情况下,您将能够在不使用$or运算符的情况下进行查询:

db.things.find({
  deleted: false,
  type: 'thing',
  ids: someid
}).sort({
  'date.created': -1
})

在这种情况下,您的索引将如下所示:

{deleted:1, type:1, ids:1, 'date.created': -1}
于 2013-02-13T11:35:43.427 回答
1

如果您可以灵活地调整架构,我建议添加一个新字段 associatedIds : [ ] 它将包含 creator._id、parent._id、一些关系._id - 您可以在更新主要对应字段时自动更新该字段,但现在您可以在此字段、type 和 created_date 上创建一个复合索引,这完全消除了查询中对 $or 的需要。

于 2013-02-18T17:51:44.730 回答
0

考虑到您对 indexing 的要求,我建议您在 $or 查询旁边使用 $orderBy 运算符。我的意思是您应该能够在 $or 查询中使用的 $or 表达式中对条件进行索引,然后您可以 $orderBy 对结果进行排序。

例如:

db.things.find({
         deleted: false,
         type: 'thing',
         $or: [{
               'creator._id': someid
              }, {
          'parent._id': someid
          }, {
          'somerelation._id': someid
          }]
        },{$orderBy:{'date.created': -1}})

上面的查询需要在 $or 表达式中的每个字段上加上在 orderBy 条件中指定的排序对象的复合索引。

例如:

db.things.ensureIndex{'parent._id': 1,"date.created":-1}
and so on for other fields.

为结果指定“限制”以防止 mongodb 执行大量内存排序是一个很好的做法。在此处阅读有关$orderBy 运算符的更多信息

于 2013-02-20T06:53:14.350 回答