MongoDB查询速度不合理,即使查询很简单并且与索引对齐

Nat*_*ley 12 mongodb

我正在运行MongoDB服务器(它实际上已经运行了).该服务器具有64GB的RAM和16个内核,以及2TB的硬盘空间可供使用.

文件结构

该数据库有一个domains包含大约2000万个文档的集合.每个文档中都有相当数量的数据,但出于我们的目的,文档的结构如下:

{
    _id: "abcxyz.com",
    LastUpdated: <date>,
    ...
}
Run Code Online (Sandbox Code Playgroud)

_id字段是文档引用的域名.LastUpdated上有一个升序索引.LastUpdated每天更新数十万条记录.基本上每次新数据可用于文档时,文档都会更新,LastUpdated字段会更新为当前日期/时间.

查询

我有一种从数据库中提取数据的机制,因此可以在Lucene索引中对其进行索引.LastUpdated字段是标记对文档所做更改的关键驱动程序.为了搜索已更改的文档并翻阅这些文档,我执行以下操作:

{
    LastUpdated: { $gte: ISODate(<firstdate>), $lt: ISODate(<lastdate>) },
    _id: { $gt: <last_id_from_previous_page> }
}

sort: { $_id:1 }
Run Code Online (Sandbox Code Playgroud)

如果没有返回文档,则开始和结束日期将继续,并且重置_id"anchor"字段.此设置可以容忍之前已更改LastUpdated值的页面中的文档,即分页不会被先前页面中现在技术上不再位于这些页面中的文档数量错误地抵消.

问题

我想理想地一次选择大约25000个文档,但由于某种原因,查询本身(即使只选择<500个文档)也非常慢.

我跑的查询是:

db.domains.find({
    "LastUpdated" : {
        "$gte" : ISODate("2011-11-22T15:01:54.851Z"),
        "$lt" : ISODate("2011-11-22T17:39:48.013Z")
    },
    "_id" : { "$gt" : "1300broadband.com" }
}).sort({ _id:1 }).limit(50).explain()
Run Code Online (Sandbox Code Playgroud)

事实上,解释(在撰写本文时)已经运行了超过10分钟并且还没有完成.我会更新这个问题,如果它完成,但当然点是查询非常慢.

我能做什么?我没有最微弱的线索,问题可能与查询有关.

编辑 55分钟后解释完成.这里是:

{
    "cursor" : "BtreeCursor Lastupdated_-1__id_1",
    "nscanned" : 13112,
    "nscannedObjects" : 13100,
    "n" : 50,
    "scanAndOrder" : true,
    "millis" : 3347845,
    "nYields" : 5454,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {
            "LastUpdated" : [
                    [
                            ISODate("2011-11-22T17:39:48.013Z"),
                            ISODate("2011-11-22T15:01:54.851Z")
                    ]
            ],
            "_id" : [
                    [
                            "1300broadband.com",
                            {

                            }
                    ]
            ]
    }
}
Run Code Online (Sandbox Code Playgroud)

Joe*_*Joe 12

归结为一个非常类似的问题,Mongodb.org上的Indexing Advice和FAQ说,引用:

范围查询也必须是索引中的最后一列

因此,如果你有密钥a,b和c并运行db.ensureIndex({a:1,b:1,c:1}),这些是"指南",以便尽可能使用索引:

好:

  • 发现(A = 1,B> 2)

  • 找到(a> 1和<10)

  • 找到(a> 1和<10).sort(a)

坏:

  • 找(a> 1,b = 2)

仅对一列使用范围查询或排序.好:

  • 发现(A = 1,B = 2)的.sort(c)中

  • 发现(A = 1,B> 2)

  • 找到(a = 1,b> 2,b <4)

  • 发现(A = 1,B> 2)的.sort(b)中

坏:

  • 发现(A> 1,B> 2)

  • 发现(A = 1,B> 2)的.sort(c)中

希望能帮助到你!

/ J

  • 嗯,它应该,或者他们声称只是在使用B树一般的查询时打破"物理定律". (2认同)

Nat*_*ley 7

好的,我解决了.罪魁祸首是"scanAndOrder": true,这表明指数没有按预期使用.正确的复合索引首先具有主要排序字段,然后是要查询的字段.

{ "_id":1, "LastUpdated":1 }
Run Code Online (Sandbox Code Playgroud)


小智 0

您是否尝试过将 _id 添加到复合索引中?当您将它用作查询的一部分时,它是否仍然需要进行全表扫描?