Performance Mongo慢速查询与3m收集

Performance Mongo慢速查询与3m收集,performance,mongodb,Performance,Mongodb,我对mongo有一些性能问题 我有这个收藏: { "_id" : ObjectId, "status" : String, "song" : ObjectId, "room" : ObjectId, "duration" : Number, "order" : 0, "addedAt" : ISODate("2016-02-09T14:16:21.331Z"), "startedAt" : ISODate("2016-02-09T1

我对mongo有一些性能问题

我有这个收藏:

{
    "_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")
}
其中我有以下索引:

/* 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在日志中向我显示这个缓慢的查询信息(缩进以便于阅读):

如您所见,执行时间为1737ms(有时甚至更长),我还体验到了高CPU利用率

有人知道为什么吗?我需要添加哪些索引?是否有太多的数据记录


谢谢

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

所以您有
room:ObjectId('myroomid')
这应该在
状态:{$in:[“结束”,“跳过”]}
之前


我假设
room:ObjectId('myroomid')
计数小于
状态:{$in:[“结束”,“跳过”]}
计数。

添加
startedAt
递减索引(-1)。如果使用
首先选择最大集。如果使用
首先选择最小的集合。这也会有所帮助

所以您有
room:ObjectId('myroomid')
这应该在
状态:{$in:[“结束”,“跳过”]}
之前

我假设
room:ObjectId('myroomid')
计数小于
状态:{$in:[“结束”,“跳过”]}
计数。

numields:4锁(micro)r:2949888
看起来不太好。
它基本上说查询被中断了4次,以便让其他操作完成。

numYields:4锁(micro)r:2949888看起来不太好。

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

尽管这里有索引交叉点不适用,但一般来说,一个好的经验法则是

MongoDB每个查询只使用一个索引

因此,您的查询位于两个字段(
status
room
)上,另外一个字段(
startedAt
)上的订单。使用的查询计划清楚地表明,它只使用
房间
上的索引。对于所有其他值,它将读取与查询的
room
部分匹配的文档,如
nscanned
nscannedObjects
所示

为了充分利用此处的索引,您需要在
房间
状态
起始位置
上使用复合索引。请注意,顺序很重要,因此如果您的查询如下所示:

db.rooms.find({
    room: someRoomId,
    status: {$in: [ "ended", "skipped" ]
}).sort({startedAt:-1})
相应的指数应为

db.rooms.createIndex({room:1,status:1,startedAt:-1})
db.rooms.createIndex({status:1,room:1,startedAt:-1})
如果您的查询看起来像

db.rooms.find({
    status: {$in: [ "ended", "skipped" ],
    room: someRoomId
}).sort({startedAt:-1})
你的索引应该是

db.rooms.createIndex({room:1,status:1,startedAt:-1})
db.rooms.createIndex({status:1,room:1,startedAt:-1})
通过相应地设置索引,您的查询应该会快得多

旁注


在您的示例中,您使用带有字符串值的
ObjectId
。这毫无意义。您可以直接使用在那里使用的字符串(例如房间号),也可以使用
new ObjectId()
返回的ObjectId()。当字段的基数足够高时(例如,由房间号给出,同一建筑中不太可能有两个房间的编号相同),无需使用ObjectId()。

尽管存在索引交点,但通常不适用于此处,但有一个好的经验法则

MongoDB每个查询只使用一个索引

因此,您的查询位于两个字段(
status
room
)上,另外一个字段(
startedAt
)上的订单。使用的查询计划清楚地表明,它只使用
房间
上的索引。对于所有其他值,它将读取与查询的
room
部分匹配的文档,如
nscanned
nscannedObjects
所示

为了充分利用此处的索引,您需要在
房间
状态
起始位置
上使用复合索引。请注意,顺序很重要,因此如果您的查询如下所示:

db.rooms.find({
    room: someRoomId,
    status: {$in: [ "ended", "skipped" ]
}).sort({startedAt:-1})
相应的指数应为

db.rooms.createIndex({room:1,status:1,startedAt:-1})
db.rooms.createIndex({status:1,room:1,startedAt:-1})
如果您的查询看起来像

db.rooms.find({
    status: {$in: [ "ended", "skipped" ],
    room: someRoomId
}).sort({startedAt:-1})
你的索引应该是

db.rooms.createIndex({room:1,status:1,startedAt:-1})
db.rooms.createIndex({status:1,room:1,startedAt:-1})
通过相应地设置索引,您的查询应该会快得多

旁注


在您的示例中,您使用带有字符串值的
ObjectId
。这毫无意义。您可以直接使用在那里使用的字符串(例如房间号),也可以使用
new ObjectId()
返回的ObjectId()。当字段的基数足够高时(例如,由房间号给出,同一建筑中不太可能有两个房间的编号相同),就不需要使用ObjectId()。

nscanned和
nscannedObjects
看起来更糟。实际上,一个yield并不表示一个中断,而是指由于各种原因导致对其他操作产生锁的查询。
nscanned
nscannedObjects
看起来更糟。实际上,一个yield并不表示一个中断,而是指由于各种原因导致锁定其他操作的查询。感谢您的详细解释,在您这方面,我不认为您指的是这个
ObjectId('myroomid')
,我只是更改了这个示例,当然有一些有效的ObjectId。为了更好地理解它,除了我已有的4个索引之外,我是否应该为3个字段添加一个索引?如果是这样的话,Mongo是否会自动使用此索引,从而使查询结构适合它?我会先添加新的索引,然后在确保一切正常后删除旧的索引,因为–是–mongodb会确定要使用哪个索引。对于use前缀
db.rooms.createIndex({startedAt:-1,状态:1,room:1})
不是更好?因为在其他查询中,您可以将startedAt前缀与此索引一起使用,而不使用status和room@ShlomiSasson在索引方面没有金子弹。你真的需要深入研究,n