MongoDB中的索引如何使查询变慢


How can an index in MongoDB render a query slower?

>**更新**

我发布了一个答案,因为它已被确认是一个问题

**源语言**

首先,我很抱歉 - 我昨天刚刚开始使用MongoDB,我在这方面仍然很陌生。我有一个非常简单的查询,使用 PHP 我的发现是这样的:

Mongo 版本是 2.0.4,运行在 CentOS 6.2 (Final) x64 上

$start = microtime(true);
$totalactive = $db->people->count(array('items'=> array('$gt' => 1)));
$end = microtime(true);
printf("Query lasted %.2f seconds'n", $end - $start);

如果没有索引,它将返回:

Query lasted 0.15 seconds

我在数据库中有 280,000 条记录。所以我认为在"项目"上添加一个索引应该会有所帮助,因为我经常查询这些数据。但令我难以置信的是,添加索引后我得到这个:

Query lasted 0.25 seconds

我做错了什么吗?

而不是计数,我用 find 来获取解释,这是输出:

> db.people.find({ 'items' : { '$gte' : 1 } }).explain();
{
"cursor" : "BtreeCursor items_1",
"nscanned" : 206396,
"nscannedObjects" : 206396,
"n" : 206396,
"millis" : 269,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
    "items" : [
        [
            1,
            1.7976931348623157e+308
        ]
    ]
}
}

如果我将查询更改为"$ne"0,则需要多花 10 毫秒!

以下是集合统计信息:

> db.people.stats()
{
"ns" : "stats.people",
"count" : 281207,
"size" : 23621416,
"avgObjSize" : 84.00009957077881,
"storageSize" : 33333248,
"numExtents" : 8,
"nindexes" : 2,
"lastExtentSize" : 12083200,
"paddingFactor" : 1,
"flags" : 0,
"totalIndexSize" : 21412944,
"indexSizes" : {
    "_id_" : 14324352,
    "items_1" : 7088592
},
"ok" : 1
}

我有 1GB 的可用内存,所以我相信索引适合内存。

以下是根据要求的人员索引:

> db.people.getIndexes()
[
{
    "v" : 1,
    "key" : {
        "_id" : 1
    },
    "ns" : "stats.people",
    "name" : "_id_"
},
{
    "v" : 1,
    "key" : {
        "items" : 1
    },
    "ns" : "stats.people",
    "name" : "items_1"
}
]

拥有索引可能有益,原因有两个:

  1. 仅访问集合的一小部分时(因为索引可以满足的限制性筛选器)。经验法则小于 10%。

  2. 当根本不需要访问集合时(因为所有必要的数据都在索引中,用于筛选和结果集)。这将由"indexOnly = true"表示。

对于"find"查询,这两种情况都不正确:您正在访问几乎整个集合(206396 281207),并且需要所有字段数据。因此,您将首先浏览索引,然后再浏览几乎整个集合,从而破坏了索引的目的。只是阅读整个集合会更快。

我本来希望"count"查询的性能更好(因为只需通过索引即可满足)。你能得到一个解释吗?

看看这个:

http://www.mongodb.org/display/DOCS/Indexing+Advice+and+FAQ#IndexingAdviceandFAQ-5.MongoDB%27s%24neor%24ninoperator%27saren%27tefficientwithindexes。

这让我考虑了这个解决方案。怎么样?

$totalactive = $db->people->count() - $db->people->count(array('items'=> array('$eq' => 1)));

这被确认为一个错误或需要在MongoDB引擎中进行优化的东西。我把它贴在mongo邮件列表中,我从Eliot Horowitz那里收到了回复。

这绝对是一个错误,或者至少是一条可以更好的路径 优化。 提出案例:https://jira.mongodb.org/browse/SERVER-5607

Priority:  Major
Fix Version/s: 2.3 desired
Type:  Bug

感谢那些帮助确认这是一个错误的人=)

你能提供这个集合中的一个对象的例子吗?"项目"字段是一个数组?如果是这样,我建议您添加一个新字段"itemCount"并在其上放置索引。在这个领域做$gt将非常快。

这是因为您的查询是接近完整的集合扫描。查询优化器选择使用该索引,而不应使用它以获得最佳性能。这是违反直觉的,是的,但这是因为光标正在遍历索引 B 树并获取树指向的文档,如果它必须扫描几乎整个树,这比仅仅遍历集合要慢。

如果您确实需要执行此类查询,并且希望将该索引用于其他操作(例如排序),则可以使用 .hint({$natural: 1}) 来告诉查询不使用索引。

巧合的是,我最近在一篇博客文章中发布了类似的问题:http://wes.skeweredrook.com/testing-with-mongodb-part-1/