2012-03-28 19 views
4

我需要一些建议来创建和排序mongo中的索引。如何在mongodb中构造复合索引

我有一个收集后用5个属性:

帖子

  • 状态
  • 开始日期
  • 结束日期
  • lowerCaseTitle
  • 中将sortOrder

几乎所有的帖子都会有相同的状态1,只有少数人会有被拒绝的状态。我所有的查询都会过滤状态,开始和结束日期,并按sortOrder进行排序。我也会有一个查询在标题上进行正则表达式搜索。

我应该在{status:1,start:1,end:1,sort:1}上设置复合键吗?我把这些字段放在复合索引中的顺序是否重要 - 我应该首先将状态放在复合索引中,因为它是最广泛的吗?对每个房产做一个复合指数而不是单一指数会更好吗? mongo只对任何给定的查询使用单个索引吗?

如果我正在做的正则表达式查询lowerCaseTitle有索引吗?

样本查询是:

db.posts.find({status: {$gte:0}, start: {$lt: today}, end: {$gt: today}}).sort({sortOrder:1}) 

db.posts.find({lowerCaseTitle: /japan/, status:{$gte:0}, start: {$lt: today}, end: {$gt: today}}).sort({sortOrder:1}) 

回答

16

这是在一个职位有很多问题;)让我去通过他们的实际顺序:

  • 每个查询都可以在最多一个索引的使用(除顶层$或条款等外)。这包括任何排序。
  • 由于上述原因,您肯定需要针对问题的复合索引而不是单独的每场索引。
  • 由于数据集的选择性非常有限,因此低基数字段(因此,数据集中具有很少唯一值的字段)通常应该不在索引中。
  • 复合指标中的字段顺序,以及复合索引中每个字段的相对方向(例如“{name:1,age:-1}”)。在mongodb.org上有很多关于复合索引和索引字段方向的文档,所以在这里我不再重复。
  • 如果排序字段位于索引中,并且是紧接在用于选择结果集的最后一个字段之后的索引中的字段,排序将仅使用索引。在大多数情况下,这将是索引的最后一个字段。

所以,你不应该在你的指数包括地位可言的,因为一旦指数走已经消除基于它最多将留下其中的大多数情况下,2-3文档更高的基数领域的绝大多数文件几乎没有通过状态索引进行优化(尤其是因为您提到这些2-3个文档很可能具有相同的状态)。

现在,与您的情况相关的最后一个注释是,当您使用范围查询(并且您是)时,它将不会使用索引进行排序。您可以通过在测试查询后查看explain()的“scanAndOrder”值来检查这一点。如果该值存在且为真,则表示它将对结果集进行内存排序(扫描和排序),而不是直接使用索引。这在您的具体情况下无法避免。

所以,你的指数因此应该是:

db.posts.ensureIndex({start:1, end:1}) 

和您的查询(修改为清楚起见顺序而已,查询优化器将通过相同的执行路径运行原来的查询,但我更喜欢把索引字段第一和order):

db.posts.find({start: {$lt: today}, end: {$gt: today}, status: {$gte:0}}).sort({sortOrder:1}) 
+1

排序键不应总是在用于查询的最后一个键之后。如果提前使用排序键,则排序会在修剪之前进行。 [这篇文章](http://architects.dzone.com/articles/cardinal-ins-mongodb-query)说明了这是有用的。 – 2013-06-30 00:21:05

+0

有趣。我会做一些测试来看看实际的真实世界的性能特点。我不得不说,我有点怀疑这是永远在现实世界情况下的性能改进(读;大数据集,范围查询的高选择性) – 2013-07-04 09:54:37

+0

@RemonvanVliet关于基数和忽略索引前缀优化,应复合索引键按最高到最低基数还是从最低到最高排序?我查阅了涉及复合索引的mongodb文档,并对这个具体问题做出了回答;尽管我假设从最高到最低。另外:从2.6开始,mongodb支持索引交集的2个索引。 – zamnuts 2015-01-19 21:18:32

相关问题