【问题标题】:MongoDB complex indicesMongoDB 复杂索引
【发布时间】:2013-12-18 17:57:27
【问题描述】:

我正在尝试了解如何最好地使用 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})

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

【问题讨论】:

    标签: mongodb database-performance query-performance indices


    【解决方案1】:

    我应该像这样创建一个复合索引吗:

    db.items.ensureIndex({年龄: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/

    【讨论】:

      【解决方案2】:

      像这样的大索引会在写入时惩罚您。最好只索引您需要的内容,让 Mongo 的优化器为您完成大部分工作。您始终可以give him an hint,或者,如果您的应用程序或数据使用情况发生剧烈变化,则在最后的情况下重新索引。

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

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

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

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

      【讨论】:

      • 假设我每天只将大约 1000 个文档添加到这个集合中,并且我在应用程序停机期间将它们全部添加到一个批次中,所以实际上我从不写入集合,只是从中读取。
      【解决方案3】:

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

      来自the docs

      “因为索引“覆盖”了查询,MongoDB 既可以匹配查询条件,也可以仅使用索引返回结果;MongoDB 不需要查看文档,只需查看索引即可完成查询。索引还可以涵盖对非分片集合的聚合管道操作。”

      一些备注:

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

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

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

      【讨论】:

      • 建立索引需要一些时间,这在编写繁重的应用程序中可能是不可接受的。当然,目录(这就是它的样子)通常不会写得很重。
      • 正确,@ixe013 这个应用程序没有以任何方式写繁重。
      猜你喜欢
      • 2014-11-13
      • 1970-01-01
      • 2013-02-14
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 2021-07-09
      • 2020-10-23
      • 1970-01-01
      相关资源
      最近更新 更多