首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >3m集合的Mongo慢查询

3m集合的Mongo慢查询
EN

Stack Overflow用户
提问于 2016-02-11 19:43:52
回答 3查看 190关注 0票数 0

我在使用mongo时遇到了一些性能问题。

我有这样的收藏:

代码语言:javascript
复制
{
    "_id" : ObjectId,
    "status" : String,
    "song" : ObjectId,
    "room" : ObjectId,
    "duration" : Number,
    "order" : 0,
    "addedAt" : ISODate("2016-02-09T14:16:21.331Z"),
    "startedAt" : ISODate("2016-02-09T14:16:21.393Z")
}

其中我有以下索引:

代码语言:javascript
复制
/* 1 */
{
    "0" : {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "mydb.mycollection"
    },
    "1" : {
        "v" : 1,
        "key" : {
            "song" : 1
        },
        "name" : "song_1",
        "ns" : "mydb.mycollection",
        "background" : true,
        "safe" : null
    },
    "2" : {
        "v" : 1,
        "key" : {
            "user" : 1
        },
        "name" : "user_1",
        "ns" : "mydb.mycollection",
        "background" : true,
        "safe" : null
    },
    "3" : {
        "v" : 1,
        "key" : {
            "room" : 1
        },
        "name" : "room_1",
        "ns" : "mydb.mycollection",
        "background" : true,
        "safe" : null
    },
    "4" : {
        "v" : 1,
        "key" : {
            "duration" : 1
        },
        "name" : "duration_1",
        "ns" : "mydb.mycollection",
        "background" : true,
        "safe" : null
    }
}

该集合中有超过300万条记录。

现在,Mongo在日志中显示了这个缓慢的查询信息(为了可读性而缩进):

代码语言:javascript
复制
2016-02-11T11:07:47.897+0000 [conn19] query mydb.mycollection query: {
    orderby: { startedAt: -1 },
    $query: { status: {$in: [ "ended", "skipped" ] }, room: ObjectId('myroomid') } }
    planSummary: IXSCAN {room: 1 }, IXSCAN { room: 1 } cursorid:64767933277   
    noreturn:10
    ntoskip:0
    nscanned:41663
    nscannedObjects:41663 keyUpdates:0
    numYields:4 locks(micros) r:2949888
    nreturned:10 realen:2668
    1737ms

如您所见,执行时间为1737ms (有时甚至更长),我也遇到过CPU利用率过高的问题。

有人知道为什么吗?有什么需要添加的索引吗?是不是3M记录的数据太多?

谢谢!

EN

回答 3

Stack Overflow用户

发布于 2016-02-11 20:07:19

尽管有一些索引交叉点在这里和一般情况下都不适用,但一个好的经验法则

MongoDB对每个查询仅使用一个索引。

因此,您的查询针对两个字段(statusroom),并按另一个字段(startedAt)排序。所使用的查询计划清楚地表明它只使用room上的索引。对于所有其他值,它读取与查询的room部分匹配的文档,如nscannednscannedObjects所示。

为了充分利用这里的索引,您需要一个针对roomstatusstartedAt的复合索引。请注意,顺序很重要,因此,如果您的查询如下所示:

代码语言:javascript
复制
db.rooms.find({
    room: someRoomId,
    status: {$in: [ "ended", "skipped" ]
}).sort({startedAt:-1})

相应的索引应该是

代码语言:javascript
复制
db.rooms.createIndex({room:1,status:1,startedAt:-1})

如果您的查询看起来像

代码语言:javascript
复制
db.rooms.find({
    status: {$in: [ "ended", "skipped" ],
    room: someRoomId
}).sort({startedAt:-1})

你的索引应该是

代码语言:javascript
复制
db.rooms.createIndex({status:1,room:1,startedAt:-1})

相应地设置索引后,您的查询速度应该会快很多。

附注

在您的示例中,您将ObjectId与字符串值一起使用。这完全说不通。您可以直接使用在那里使用的字符串(比如房间号),也可以使用new ObjectId()返回的ObjectId()。当字段的基数足够高时(例如,由房间号提供),则不需要使用ObjectId(),因为同一建筑物中不太可能有两个房间具有相同的房间号。

票数 4
EN

Stack Overflow用户

发布于 2016-02-11 20:02:16

numYields:4 locks(micros) r:2949888看起来并不好。

它基本上是说,查询被中断了4次,以便让其他操作完成。

票数 1
EN

Stack Overflow用户

发布于 2016-02-11 19:53:51

添加startedAt降序索引(-1)。如果您使用or,请首先选择最大集。如果使用and,请首先选择最小的集合。这也会有所帮助。

所以你有room: ObjectId('myroomid'),这应该在status: {$in: [ "ended", "skipped" ] }之前。

我假设room: ObjectId('myroomid')计数小于status: {$in: [ "ended", "skipped" ] }计数。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35338448

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档