创建索引后第一次查询很慢

3
我在一个集合中添加了索引。第一次查询比没有索引的查询要慢。后续查询比没有索引的查询要快,这是有道理的。
我想知道为什么会出现这种情况,是因为索引需要从磁盘读取到内存吗?更难理解的是,我删除了索引,重启了mongod,再次创建索引时速度很快,不像第一次那样慢。如果我重新启动计算机,则带索引的第一次查询会变得很慢。
有人能清楚地解释这种行为吗?
接下来,我提供一些关于文档、索引和查询信息的资料。集合中的文档如下:
> db.posts.findOne()
{
        "_id" : ObjectId("557d73e1fab73211b00f3080"),
        "title" : "aaa",
        "author" : "nuevo",
        "body" : "aaa",
        "permalink" : "aaa",
        "tags" : [
                "a"
        ],
        "comments" : [ ],
        "date" : ISODate("2015-06-14T12:30:25.733Z")
}

集合的大小:

> db.posts.find().count()
1008

没有索引的查询,需要3毫秒(我没有放出explain的所有输出,只有相关部分):

> db.posts.explain("executionStats").find({ permalink: "ambzrbxvnorazgnqvzbw"});

{
....
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 3,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 1008,
....
}

创建索引:

> db.posts.createIndex({permalink:1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 3,
        "numIndexesAfter" : 4,
        "ok" : 1
}

使用已创建的索引进行查询(71毫秒):

> db.posts.explain("executionStats").find({ permalink: "ambzrbxvnorazgnqvzbw"});

{
....
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 71,
                "totalKeysExamined" : 1,
                "totalDocsExamined" : 1,
....
}

重新使用其他永久链接来重新运行相同的查询,以避免从内存中获取该查询(或类似操作)。此过程只需0毫秒:
> db.posts.explain("executionStats").find({ permalink: "orrjnueekntvjegzvbjk"});

{
....
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 0,
                "totalKeysExamined" : 1,
                "totalDocsExamined" : 1,
....
}
1个回答

2
你是否在使用Linux? Linux将所有的空闲内存用作磁盘缓存。即使在重新启动Mongo之后,该缓存仍然存在,直到系统需要它来处理其他事情为止。命中缓存的查询即使没有索引也会很快,因为它们命中了内存。有一些命令可以确认这一点-检查缓存命中和未命中。
未缓冲读取(必须命中硬盘上的盘片)比内存读取慢数百倍或更多(无论要读取多少数据;驱动器缓存、内存缓冲区等都会提前读取兆字节,即使你只需要一个字节)。请参见https://gist.github.com/jboner/2841832以获取一些实际数字。
我认为如果你查看http://docs.mongodb.org/manual/administration/analyzing-mongodb-performance/#administration-monitoring-page-faultshttp://docs.mongodb.org/manual/reference/glossary/#term-page-fault,你将能够确认慢速访问基本上是100%的页面错误(需要从硬盘读取所有信息),而快速访问将接近100%的命中(缓存读取)。

不,我使用的是64位的Windows 8操作系统。 - Weslor
1
我非常确定Windows也将物理内存用作磁盘缓存。我认为在任务管理器的性能选项卡中显示的是“缓存”内存。 因此,与Linux上的一般思路相同。 - Bartosz Bilicki

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