MongoDB覆盖索引无效。

3

我有一个国家文档,看起来像这样:

{
  "_id" : ObjectId("4e493af4140700590800154f"),
  "geoname_id" : "49518",
  "code" : "rw",
  "names" : {
    "en" : "Rwanda",
    "nl" : "Rwanda",
    "de" : "Ruanda"
  }
}

为了只在查询时触及索引:

db.countries.find({}, {"names.en":1, _id:0})

我添加了以下索引:

db.countries.ensureIndex({"names.en":1})

据我了解,此查询现在应只涉及索引。 然而,.explain()告诉我查询根本没有使用任何索引:
{
  "cursor" : "BasicCursor",
  "nscanned" : 247,
  "nscannedObjects" : 247,
  "n" : 247,
  "millis" : 0,
  "nYields" : 0,
  "nChunkSkips" : 0,
  "isMultiKey" : false,
  "indexOnly" : false,
  "indexBounds" : {
  }
}

我认为原因可能是完整数据库将被输出(247个国家),但这对我来说毫无意义。当国家在索引内可用时,应使用索引,对吗?

有人有什么想法吗?

谢谢

3个回答

2

没有使用索引的原因是因为您没有查询任何条件。没有查询条件,查询优化器将不会选择要使用的索引,因此不能作为覆盖索引运行。

尝试 db.countries.find({"names.en":"Rwanda"}, {"names.en":1, _id:0}).explain() 来验证具有索引条件时它实际上会命中适当的索引。

可以提出一个关于 MongoDB 需要足够聪明以意识到它可以使用索引来满足原始查询的论点,但目前它并没有这样做。您可以使用 .sort({"names.en":1}) 使其也选择索引。


所以,要完全清楚:除非我重新构建文档以便可以按照某个条件查询,比如“语言:英语”,否则无法仅通过索引获取完整的国家列表。 - fightbulc
不确定是否需要重构,因为以 {"names.en":{$ne:"None"}} 作为条件的话,会与 {} 命中相同的列表。但是是的,你需要在命中索引之前设置条件。 - Remon van Vliet
没问题。请注意,使用.sort()也会使用索引。 - Remon van Vliet
另外请注意,当输出字段之一是指向子文档中的字段的点路径时,MongoDB目前不会使用覆盖索引。您可以在https://jira.mongodb.org/browse/SERVER-2104上观看和投票以跟踪此问题。 - dcrosta
@dcrosta:没错,我在尝试使用索引来观察“indexOnly”何时变为“true”时也注意到了这一点。感谢您的建议。我习惯于MySQL的索引,因此希望mongodb的表现类似。 - fightbulc

0

使用排序将确保它仅使用索引进行排序。

将“查找”和“排序”视为两个独立的操作。


0

目前,您可以提示Mongo使用您想要的索引(ref):

db.countries.find({}, {"names.en":1, _id:0}).hint({"names.en":1})

我不确定这个功能是什么时候添加的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接