我有一组推文,其中包含userid和tweeted_at(date)的索引。我想在用户的集合中找到最旧和最新推文的日期,但查询运行速度非常慢。
我用过解释,这就是我得到的。我试着阅读文档进行解释,但我不明白这里发生了什么。解释只是排序吗?如果是这样,为什么在使用索引时需要这么长时间?
> db.tweets.find({userid:50263}).sort({tweeted_at:-1}).limit(1).explain(1)
{
"cursor" : "BtreeCursor tweeted_at_1 reverse",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 12705,
"nscanned" : 12705,
"nscannedObjectsAllPlans" : 12705,
"nscannedAllPlans" : 12705,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 188,
"nChunkSkips" : 0,
"millis" : 7720,
"indexBounds" : {
"tweeted_at" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
},
"allPlans" : [
{
"cursor" : "BtreeCursor tweeted_at_1 reverse",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 12705,
"nscanned" : 12705,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"tweeted_at" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
}
}
],
"server" : "adams-server:27017",
"filterSet" : false,
"stats" : {
"type" : "LIMIT",
"works" : 12807,
"yields" : 188,
"unyields" : 188,
"invalidates" : 0,
"advanced" : 0,
"needTime" : 12705,
"needFetch" : 101,
"isEOF" : 1,
"children" : [
{
"type" : "FETCH",
"works" : 12807,
"yields" : 188,
"unyields" : 188,
"invalidates" : 0,
"advanced" : 0,
"needTime" : 12705,
"needFetch" : 101,
"isEOF" : 1,
"alreadyHasObj" : 0,
"forcedFetches" : 0,
"matchTested" : 0,
"children" : [
{
"type" : "IXSCAN",
"works" : 12705,
"yields" : 188,
"unyields" : 188,
"invalidates" : 0,
"advanced" : 12705,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 1,
"keyPattern" : "{ tweeted_at: 1.
0 }",
"boundsVerbose" : "field #0['twe
eted_at']: [MaxKey, MinKey]",
"isMultiKey" : 0,
"yieldMovedCursor" : 0,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0,
"keysExamined" : 12705,
"children" : [ ]
}
]
}
]
}
}
>
> db.tweets.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "honeypot.tweets"
},
{
"v" : 1,
"unique" : true,
"key" : {
"tweet_id" : 1
},
"name" : "tweet_id_1",
"ns" : "honeypot.tweets",
"dropDups" : true
},
{
"v" : 1,
"key" : {
"tweeted_at" : 1
},
"name" : "tweeted_at_1",
"ns" : "honeypot.tweets"
},
{
"v" : 1,
"key" : {
"keywords" : 1
},
"name" : "keywords_1",
"ns" : "honeypot.tweets"
},
{
"v" : 1,
"key" : {
"user_id" : 1
},
"name" : "user_id_1",
"ns" : "honeypot.tweets"
}
]
>
答案 0 :(得分:4)
通过查看光标字段,您可以看到使用了哪个索引:
"cursor" : "BtreeCursor tweeted_at_1 reverse",
BtreeCursor
表示查询使用了索引,tweeted_at_1 reverse
是使用的索引的名称。
您应该查看解释中每个字段的documentation,以查看每个字段的详细说明。
您的查询持续了7720毫秒(milis
),扫描了12705个文档(nscanned
)。
查询速度很慢,因为MongoDB扫描了符合条件的所有文档。发生这种情况是因为MongoDB没有使用您的索引进行查询,而是用于对数据进行排序。
要创建将用于查询和排序的索引,您应该创建compound index。复合索引是引用多个字段的单个索引结构。您可以创建最多31个字段的复合索引。您可以创建这样的复合索引(顺序或字段很重要):
db.tweets.ensureIndex({userid: 1, tweeted_at: -1});
此索引将用于搜索userid
字段并按tweeted_at字段排序。
您可以阅读并查看有关添加用于排序here的索引的更多示例。
修改强>
如果您有其他索引,MongoDB可能正在使用它们。在测试查询性能时,可以使用hint
来使用特定索引。
在测试查询的性能时,您应该始终进行多项测试并采取约。结果。
此外,如果查询速度很慢,即使使用索引,我也会检查服务器上是否有足够的内存。从磁盘加载数据比从内存加载慢几个数量级。您应该始终确保有足够的RAM,以便所有数据和索引都适合内存。
答案 1 :(得分:0)
看起来你需要在tweeted_at和userid上创建一个索引。
db.tweets.ensureIndex({'tweeted_at':1, 'userid':1})
这应该使查询确实非常快(但是以存储和插入时间为代价)