MongoDB复杂索引

时间:2013-12-02 21:30:21

标签: mongodb database-performance query-performance indices

我正在尝试了解如何最好地使用MongoDB中的索引。让我们说我有一个像这样的文档集合:

{
  _id:        1,
  keywords:   ["gap", "casual", "shorts", "oatmeal"],
  age:        21,
  brand:     "Gap",
  color:     "Black",
  gender:    "female",     
  retailer:  "Gap",
  style:     "Casual Shorts",
  student:    false,
  location:  "US",
}

我定期运行查询以查找符合以下每个字段的一组条件的所有文档,例如:

db.items.find({ age:      { $gt: 13, $lt: 40 },
                brand:    { $in: ['Gap', 'Target'] },
                retailer: { $in: ['Gap', 'Target'] },
                gender:   { $in: ['male', 'female'] },
                style:    { $in: ['Casual Shorts', 'Jeans']},
                location: { $in: ['US', 'International'] },
                color:    { $in: ['Black', 'Green'] },
                keywords: { $all: ['gap', 'casual'] }
              })

我正在尝试计算我可以创建哪种索引来提高查询速度,例如这样。我应该创建这样的复合索引:

db.items.ensureIndex({ age: 1, brand: 1, retailer: 1, gender: 1, style: 1, location: 1, color: 1, keywords: 1})

或者我可以创建一组更好的索引来优化此查询吗?

3 个答案:

答案 0 :(得分:2)

  

我应该创建这样的复合索引:

     

db.items.ensureIndex({age:1,品牌:1,零售商:1,性别:1,样式:1,位置:1,颜色:1,关键字:1})

您可以像上面那样创建一个索引,但几乎是整个集合的索引。索引占用空间;索引中的字段越多,使用的空间就越多。通常是RAM,虽然它们可以换掉。他们还会受到处罚。

您的索引似乎很浪费,因为可能仅仅索引其中一些字段会使MongoDB扫描一组接近查找操作预期结果的文档。

  

我可以创建一组更好的索引来优化此查询吗?

就像我之前说的那样,可能是的。但是这个问题很难在不知道收集细节的情况下回答,比如它有多少文件,每个领域可以有哪些价值,这些价值如何在收集中分配(50%性别男性,50%性别女性?) ,它们如何相互关联等等。

有一些索引策略,但通常您应该努力创建具有高选择性的索引。选择“小”字段组合,这将有助于MongoDB找到扫描“合理”数量的所需文档。同样,“小”和“合理”将取决于您正在执行的集合和查询的特征。

由于这是一个相当复杂的主题,因此这里有一些参考资料可以帮助您构建更合适的索引。

http://emptysqua.re/blog/optimizing-mongodb-compound-indexes/ http://docs.mongodb.org/manual/faq/indexes/#how-do-you-determine-what-fields-to-index http://docs.mongodb.org/manual/tutorial/create-queries-that-ensure-selectivity/

并使用cursor.explain评估您的索引。

http://docs.mongodb.org/manual/reference/method/cursor.explain/

答案 1 :(得分:0)

像这样的大型索引会在写入时惩罚你。最好只为您需要的索引编制索引,让Mongo的优化程序为您完成大部分工作。如果您的应用程序或数据使用情况发生巨大变化,您可以随时give him an hint或最后重新索引。

您的查询将使用具有一个(快速)的字段的索引,并对其余文档使用表扫描(慢速)。

根据您的应用程序,一些独立的索引可能会更好。添加更多索引不会提高性能。凭借写作能力,它甚至可能使情况变得更糟(YMMV)。

以下是选择要放入索引的字段的基本算法:

  • 查询中最常见的单个字段是什么?
  • 如果查询中存在单个字段,表扫描是否会很昂贵?
  • 您可以索引哪些其他字段以进一步减少表扫描?

答案 2 :(得分:0)

对于您的查询,此索引似乎非常合理。 MongoDB将查询调用为此索引的覆盖查询,因为不需要访问文档。可以从索引中获取所有数据。

来自the docs

“因为索引”覆盖“了查询,所以MongoDB可以匹配查询条件并仅使用索引返回结果; MongoDB不需要查看文档,只需查看索引即可完成查询。还可以覆盖未加密集合上的聚合管道操作。“

一些评论:

  • 此索引仅供包含年龄过滤器的查询使用。仅按品牌或零售商过滤的查询可能不会使用此索引。

  • 仅在查询的一个或两个最具选择性的字段上添加索引,这将带来非常显着的性能提升。您添加的字段越多,索引大小就越大。

  • 您可能希望生成一些随机样本数据,并使用不同的索引或索引集来衡量其性能。这显然是最安全的了解方式。