MongoDB:索引内的查询非常缓慢

3
我看到了很多类似的问题,但它们没有解决我的问题(1, 2, 3)。
我有一个包含近200万个文档的集合。我的问题是:非常简单的查询(find({id: 53}))运行时间接近5分钟(请见下面的所有相关信息)。
我尝试通过"id"字段添加索引,并尝试使用提示,scanAndOrder为false。我有足够的内存(目前没有交换,在服务器上仅使用了600MB,仍然有约1GB的空闲空间)。这是debian 7和mongodb 2.4.7。
也许这很重要:昨天我运行了repairDatabase,之后注意到了这个问题(但我不能确定它之前是否存在)。但无论如何,我对集合进行了完整验证,一切似乎都没问题。昨天我还添加了一个索引({id:1})。今天我重新索引了集合。
在所有这样长的查询中,我的磁盘使用非常广泛。
> db.results.count()
1819411

> db.results.stats()
{
    "ns" : "spider.results",
    "count" : 1819411,
    "size" : 26662218768,
    "avgObjSize" : 14654.313273911172,
    "storageSize" : 28309077856,
    "numExtents" : 34,
    "nindexes" : 4,
    "lastExtentSize" : 2146426864,
    "paddingFactor" : 1,
    "systemFlags" : 0,
    "userFlags" : 0,
    "totalIndexSize" : 207245248,
    "indexSizes" : {
        "_id_" : 53144000,
        "datetime_-1" : 45793776,
        "id_1_datetime_1" : 62513696,
        "id_1" : 45793776
    },
    "ok" : 1
}

> db.results.getIndices()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "ns" : "spider.results",
        "name" : "_id_"
    },
    {
        "v" : 1,
        "key" : {
            "datetime" : -1
        },
        "ns" : "spider.results",
        "name" : "datetime_-1"
    },
    {
        "v" : 1,
        "key" : {
            "id" : 1,
            "datetime" : 1
        },
        "unique" : true,
        "ns" : "spider.results",
        "name" : "id_1_datetime_1"
    },
    {
        "v" : 1,
        "key" : {
            "id" : 1
        },
        "ns" : "spider.results",
        "name" : "id_1"
    }
]

> db.results.validate(true)
{
    "ns" : "spider.results",
    "firstExtent" : "0:258000 ns:spider.results",
    "lastExtent" : "18:2000 ns:spider.results",
    "extentCount" : 34,
    "extents" : [
        {
            "loc" : "0:258000",
            "xnext" : "0:25a000",
            "xprev" : "null",
            "nsdiag" : "spider.results",
            "size" : 8192,
            "firstRecord" : "0:2580b0",
            "lastRecord" : "0:2598b0"
        },
        {
            "loc" : "0:25a000",
            "xnext" : "0:29d000",
            "xprev" : "0:258000",
            "nsdiag" : "spider.results",
            "size" : 274432,
            "firstRecord" : "0:25a0b0",
            "lastRecord" : "0:29c6b0"
        },
        {
            "loc" : "0:29d000",
            "xnext" : "0:3a9000",
            "xprev" : "0:25a000",
            "nsdiag" : "spider.results",
            "size" : 1097728,
            "firstRecord" : "0:29d0b0",
            "lastRecord" : "0:3a6c30"
        },
        {
            "loc" : "0:3a9000",
            "xnext" : "0:7d9000",
            "xprev" : "0:29d000",
            "nsdiag" : "spider.results",
            "size" : 4390912,
            "firstRecord" : "0:3a90b0",
            "lastRecord" : "0:7d8ab0"
        },
        {
            "loc" : "0:7d9000",
            "xnext" : "0:d81000",
            "xprev" : "0:3a9000",
            "nsdiag" : "spider.results",
            "size" : 5931008,
            "firstRecord" : "0:7d90b0",
            "lastRecord" : "0:d7fcb0"
        },
        {
            "loc" : "0:d81000",
            "xnext" : "0:1524000",
            "xprev" : "0:7d9000",
            "nsdiag" : "spider.results",
            "size" : 8007680,
            "firstRecord" : "0:d810b0",
            "lastRecord" : "0:15238b0"
        },
        {
            "loc" : "0:1524000",
            "xnext" : "0:1f74000",
            "xprev" : "0:d81000",
            "nsdiag" : "spider.results",
            "size" : 10813440,
            "firstRecord" : "0:15240b0",
            "lastRecord" : "0:1f73ab0"
        },
        {
            "loc" : "0:1f74000",
            "xnext" : "1:2000",
            "xprev" : "0:1524000",
            "nsdiag" : "spider.results",
            "size" : 14598144,
            "firstRecord" : "0:1f740b0",
            "lastRecord" : "0:2d5f6b0"
        },
        {
            "loc" : "1:2000",
            "xnext" : "1:12ce000",
            "xprev" : "0:1f74000",
            "nsdiag" : "spider.results",
            "size" : 19709952,
            "firstRecord" : "1:20b0",
            "lastRecord" : "1:12cd8b0"
        },
        {
            "loc" : "1:12ce000",
            "xnext" : "1:2c2f000",
            "xprev" : "1:2000",
            "nsdiag" : "spider.results",
            "size" : 26611712,
            "firstRecord" : "1:12ce0b0",
            "lastRecord" : "1:2c2eab0"
        },
        {
            "loc" : "1:2c2f000",
            "xnext" : "1:4e72000",
            "xprev" : "1:12ce000",
            "nsdiag" : "spider.results",
            "size" : 35926016,
            "firstRecord" : "1:2c2f0b0",
            "lastRecord" : "1:4e719b0"
        },
        {
            "loc" : "1:4e72000",
            "xnext" : "2:2000",
            "xprev" : "1:2c2f000",
            "nsdiag" : "spider.results",
            "size" : 48500736,
            "firstRecord" : "1:4e720b0",
            "lastRecord" : "1:7cb27b0"
        },
        {
            "loc" : "2:2000",
            "xnext" : "2:3e74000",
            "xprev" : "1:4e72000",
            "nsdiag" : "spider.results",
            "size" : 65478656,
            "firstRecord" : "2:20b0",
            "lastRecord" : "2:3e71d30"
        },
        {
            "loc" : "2:3e74000",
            "xnext" : "3:2000",
            "xprev" : "2:2000",
            "nsdiag" : "spider.results",
            "size" : 88399872,
            "firstRecord" : "2:3e740b0",
            "lastRecord" : "2:92c1ab0"
        },
        {
            "loc" : "3:2000",
            "xnext" : "3:71d2000",
            "xprev" : "2:3e74000",
            "nsdiag" : "spider.results",
            "size" : 119341056,
            "firstRecord" : "3:20b0",
            "lastRecord" : "3:71d1ab0"
        },
        {
            "loc" : "3:71d2000",
            "xnext" : "3:10b78000",
            "xprev" : "3:2000",
            "nsdiag" : "spider.results",
            "size" : 161112064,
            "firstRecord" : "3:71d20b0",
            "lastRecord" : "3:10b70ab0"
        },
        {
            "loc" : "3:10b78000",
            "xnext" : "4:2000",
            "xprev" : "3:71d2000",
            "nsdiag" : "spider.results",
            "size" : 217501696,
            "firstRecord" : "3:10b780b0",
            "lastRecord" : "3:1dae29b0"
        },
        {
            "loc" : "4:2000",
            "xnext" : "4:11809000",
            "xprev" : "3:10b78000",
            "nsdiag" : "spider.results",
            "size" : 293629952,
            "firstRecord" : "4:20b0",
            "lastRecord" : "4:118088b0"
        },
        {
            "loc" : "4:11809000",
            "xnext" : "5:2000",
            "xprev" : "4:2000",
            "nsdiag" : "spider.results",
            "size" : 396402688,
            "firstRecord" : "4:118090b0",
            "lastRecord" : "4:29212930"
        },
        {
            "loc" : "5:2000",
            "xnext" : "5:1fe5d000",
            "xprev" : "4:11809000",
            "nsdiag" : "spider.results",
            "size" : 535146496,
            "firstRecord" : "5:20b0",
            "lastRecord" : "5:1fe5ca30"
        },
        {
            "loc" : "5:1fe5d000",
            "xnext" : "6:2000",
            "xprev" : "5:2000",
            "nsdiag" : "spider.results",
            "size" : 722448384,
            "firstRecord" : "5:1fe5d0b0",
            "lastRecord" : "5:4af553b0"
        },
        {
            "loc" : "6:2000",
            "xnext" : "7:2000",
            "xprev" : "5:1fe5d000",
            "nsdiag" : "spider.results",
            "size" : 975306752,
            "firstRecord" : "6:20b0",
            "lastRecord" : "6:3a21d6b0"
        },
        {
            "loc" : "7:2000",
            "xnext" : "8:2000",
            "xprev" : "6:2000",
            "nsdiag" : "spider.results",
            "size" : 1316667392,
            "firstRecord" : "7:20b0",
            "lastRecord" : "7:4e7ab0b0"
        },
        {
            "loc" : "8:2000",
            "xnext" : "9:2000",
            "xprev" : "7:2000",
            "nsdiag" : "spider.results",
            "size" : 1777504256,
            "firstRecord" : "8:20b0",
            "lastRecord" : "8:69f278b0"
        },
        {
            "loc" : "9:2000",
            "xnext" : "10:2000",
            "xprev" : "8:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "9:20b0",
            "lastRecord" : "9:7fefdab0"
        },
        {
            "loc" : "10:2000",
            "xnext" : "11:2000",
            "xprev" : "9:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "10:20b0",
            "lastRecord" : "10:7feff630"
        },
        {
            "loc" : "11:2000",
            "xnext" : "12:2000",
            "xprev" : "10:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "11:20b0",
            "lastRecord" : "11:7feffa30"
        },
        {
            "loc" : "12:2000",
            "xnext" : "13:2000",
            "xprev" : "11:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "12:20b0",
            "lastRecord" : "12:7feffb30"
        },
        {
            "loc" : "13:2000",
            "xnext" : "14:2000",
            "xprev" : "12:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "13:20b0",
            "lastRecord" : "13:7fefb7b0"
        },
        {
            "loc" : "14:2000",
            "xnext" : "15:2000",
            "xprev" : "13:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "14:20b0",
            "lastRecord" : "14:7feffb30"
        },
        {
            "loc" : "15:2000",
            "xnext" : "16:2000",
            "xprev" : "14:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "15:20b0",
            "lastRecord" : "15:7fefba30"
        },
        {
            "loc" : "16:2000",
            "xnext" : "17:2000",
            "xprev" : "15:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "16:20b0",
            "lastRecord" : "16:7feff9b0"
        },
        {
            "loc" : "17:2000",
            "xnext" : "18:2000",
            "xprev" : "16:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "17:20b0",
            "lastRecord" : "17:7feff9b0"
        },
        {
            "loc" : "18:2000",
            "xnext" : "null",
            "xprev" : "17:2000",
            "nsdiag" : "spider.results",
            "size" : 2146426864,
            "firstRecord" : "18:20b0",
            "lastRecord" : "18:1f8328b0"
        }
    ],
    "datasize" : 26662218768,
    "nrecords" : 1819411,
    "lastExtentSize" : 2146426864,
    "padding" : 1,
    "firstExtentDetails" : {
        "loc" : "0:258000",
        "xnext" : "0:25a000",
        "xprev" : "null",
        "nsdiag" : "spider.results",
        "size" : 8192,
        "firstRecord" : "0:2580b0",
        "lastRecord" : "0:2598b0"
    },
    "lastExtentDetails" : {
        "loc" : "18:2000",
        "xnext" : "null",
        "xprev" : "17:2000",
        "nsdiag" : "spider.results",
        "size" : 2146426864,
        "firstRecord" : "18:20b0",
        "lastRecord" : "18:1f8328b0"
    },
    "objectsFound" : 1819411,
    "invalidObjects" : 0,
    "bytesWithHeaders" : 26691329344,
    "bytesWithoutHeaders" : 26662218768,
    "deletedCount" : 14,
    "deletedSize" : 1617742528,
    "nIndexes" : 4,
    "keysPerIndex" : {
        "spider.results.$_id_" : 1819411,
        "spider.results.$datetime_-1" : 1819411,
        "spider.results.$id_1_datetime_1" : 1819411,
        "spider.results.$id_1" : 1819411
    },
    "valid" : true,
    "errors" : [ ],
    "ok" : 1
}

> db.results.find({id:6}).explain()
{
    "cursor" : "BtreeCursor id_1_datetime_1",
    "isMultiKey" : false,
    "n" : 47402,
    "nscannedObjects" : 47402,
    "nscanned" : 47402,
    "nscannedObjectsAllPlans" : 47402,
    "nscannedAllPlans" : 47402,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 248,
    "nChunkSkips" : 0,
    "millis" : 254485,
    "indexBounds" : {
        "id" : [
            [
                6,
                6
            ]
        ],
        "datetime" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ]
    },
    "server" : "ip-10-137-56-52:27017"
}

我还没有完成的一件事是备份并修复,然后恢复。但我不确定这是否有帮助...

有什么建议吗?


搜索该“id”返回了47,000个文档。这符合您的预期吗? - WiredPrairie
它也是一个非常大的数据库——28GB?您确定您的系统有足够的内存来处理工作集吗?给定平均文档大小,加载47000个文档意味着要加载约650MB的数据。 - WiredPrairie
顺便提一下,_id上不需要创建索引,因为Mongo会自动完成。或者您可能有另一个称为"id"的字段。 - EmptyArsenal
谢谢。实际上,数据库很大,同时可能存在许多具有相同“id”字段的文档。从htop中可以看到机器上有足够的资源。但不幸的是,这里似乎是我的错。首先,我尝试了一个类似的查询({id: 5, revision: 1}),它没有索引。它花费了约10分钟(并且没有返回任何结果)。该查询的解释也需要大约相同的时间。然后我尝试了带有索引的查询{id:5}的解释。这需要5-7分钟,具体取决于ID。但是,后来我发现,没有解释的真正查询运行得很快。对于浪费您的时间,我感到非常抱歉:( - Serge
所以我的结论是:查询的解释时间与查询的实际执行时间不同。 - Serge
没有解释时间是指解释的时间,而不是查询的时间。 - Sammaye
1个回答

3

看起来你给出的id为6的查询示例匹配了47402个文档:

> db.results.find({id:6}).explain()
    "n" : 47402,

文档的平均大小约为14654字节:

> db.results.stats()
    "avgObjSize" : 14654.313273911172,

您认为这种情况符合您的观点吗?

这意味着此查询返回的结果大小约为662 MB。如果存储器中没有这662 MB的文档,必须从磁盘获取,则会产生大量磁盘活动并且查询需要很长时间。

根据您的应用程序要求,有几种方法可以提高性能:

  • 使用更具体的查询匹配较少的文档。例如,使用_id来获取单个文档或在查询中指定日期时间以及ID。

  • 重构文档模式,使您希望查询的文档变小。

  • 在查询中使用投影仅选择14KB文档的子集返回,并建立包含该查询投影中的字段的索引,以便可以完全从索引中满足查询。但是请注意,只有选择文档的小子集,使得索引不会变得过大,才能使此方法奏效,否则您将重新陷入页面索引的磁盘读写问题。db.results.stats()输出告诉您索引大小。

  • 为服务器配备足够的内存,以使集合完全保留在内存中。集合大小约为26 GB,因此对于此方法,您至少需要相同数量的内存:

    db.results.stats() "size" : 26662218768,

希望这能对您有所帮助,

Bruce


感谢您非常有帮助的回答。文档之所以很大,是因为我在其中保存了大量的文本内容(并非全部) - 也许我应该将它们移动到另一个集合中,并仅保存引用。但正如我上面所评论的,我找到了缓慢解释的真正原因,这就是为什么我的问题现在得到了解决(解释的时间不是实际查询的时间)。 - Serge
请注意,在解释您的时间实验时,要记住同一操作的时间会因为信息是否在内存中而有所不同。例如,如果您进行一个返回600MB结果的查询,第一次会很慢,因为它必须从磁盘读取600MB,但第二次会很快,因为这600MB将在内存中。当您比较explain()和find()的结果时,也可能会出现相同的情况。 - Bruce Lucas

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