Performance Mongo慢速查询与3m收集
我对mongo有一些性能问题 我有这个收藏: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
{
"_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