mongo 与 java 代码和 shell 花费不同时间的查询
mongo query which costs different time from java code and shell
我有一个 mongo 查询,它花费的时间与 java 代码和 shell 不同。
Java 代码如下,
mongo服务器版本是v2.6.5,v2.4.8版本没有问题
DBObject obj = new BasicDBObject();
obj.put("accountId",accountId);
List<DBObject> listOr = new ArrayList<DBObject>();
listOr.add(new BasicDBObject("status", 11));
listOr.add(new BasicDBObject("status", 12));
obj.put("$or", listOr);
BasicDBObject andDB = new BasicDBObject();
andDB.append("$gt", 0);
andDB.append("$lt",4514185);
obj.put("currBoardId",andDB);
DBCursor cur = null;
cur = coll.find(obj,new BasicDBObject("currBoardId",1)).sort(new BasicDBObject("commentId",-1)).limit(10);
当我 运行 代码时,我可以从配置文件集合中获取慢查询记录。它显示 "nscanned" : 1566031 和 "millis" : 4724 .
> db.system.profile.find().sort({$natural:-1}).limit(10);
{ "op" : "query", "ns" : "l_comment.comment", "query" : { "$query" : { "accountId" : NumberLong(4), "$or" : [ { "status" : 11 }, { "status" : 12 } ], "currBoardId" : { "$gt" : 0, "$lt" : NumberLong(4514185) } }, "$orderby" : { "commentId" : -1 } }, "cursorid" : 220355902849, "ntoreturn" : 10, "ntoskip" : 0, "nscanned" : 1566031, "nscannedObjects" : 1566031, "keyUpdates" : 0, "numYield" : 5, "lockStats" : { "timeLockedMicros" : { "r" : NumberLong(8921271), "w" : NumberLong(0) }, "timeAcquiringMicros" : { "r" : NumberLong(14), "w" : NumberLong(2) } }, "nreturned" : 10, "responseLength" : 410, "millis" : 4724, "execStats" : { "type" : "PROJECTION", "works" : 1566031, "yields" : 12234, "unyields" : 12234, "invalidates" : 0, "advanced" : 10, "needTime" : 0, "needFetch" : 0, "isEOF" : 0, "children" : [ { "type" : "FETCH", "works" : 1566031, "yields" : 12234, "unyields" : 12234, "invalidates" : 0, "advanced" : 10, "needTime" : 1566021, "needFetch" : 0, "isEOF" : 0, "alreadyHasObj" : 0, "forcedFetches" : 0, "matchTested" : 10, "children" : [ { "type" : "IXSCAN", "works" : 1566031, "yields" : 12234, "unyields" : 12234, "invalidates" : 0, "advanced" : 1566031, "needTime" : 0, "needFetch" : 0, "isEOF" : 0, "keyPattern" : "{ commentId: -1.0 }", "isMultiKey" : 0, "boundsVerbose" : "field #0['commentId']: [MaxKey, MinKey]", "yieldMovedCursor" : 0, "dupsTested" : 0, "dupsDropped" : 0, "seenInvalidated" : 0, "matchTested" : 0, "keysExamined" : 1566031, "children" : [ ] } ] } ] }, "ts" : ISODate("2015-02-10T08:51:16.195Z"), "client" : "192.168.66.103", "allUsers" : [ ], "user" : "" }
但是当我 运行 来自 shell 的查询时,它 returns 很快。
db.comment.find({ "accountId" : NumberLong(4), "$or" : [ { "status" : 11 }, { "status" : 12 } ], "currBoardId" : { "$gt" : 0, "$lt" : NumberLong(4514185) }}).sort({commentId:-1}).limit(10)
下面是解释的输出。它显示查询扫描 10517 条记录并使用 109 毫秒。
为什么会这样,我该如何改进代码?
感谢任何提示和帮助。
{
"clauses" : [
{
"cursor" : "BtreeCursor idx_atst",
"isMultiKey" : false,
"n" : 10,
"nscannedObjects" : 10517,
"nscanned" : 10517,
"scanAndOrder" : true,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"accountId" : [
[
NumberLong(4),
NumberLong(4)
]
],
"rootId" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"status" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"type" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor ",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"scanAndOrder" : true,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"accountId" : [
[
NumberLong(4),
NumberLong(4)
]
],
"rootId" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"status" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"type" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}
],
"cursor" : "QueryOptimizerCursor",
"n" : 10,
"nscannedObjects" : 10517,
"nscanned" : 10517,
"nscannedObjectsAllPlans" : 31574,
"nscannedAllPlans" : 31574,
"scanAndOrder" : false,
"nYields" : 246,
"nChunkSkips" : 0,
"millis" : 109,
"server" : "app-sz-2-3.sz.chosk.net:27017",
"filterSet" : false,
"stats" : {
"type" : "KEEP_MUTATIONS",
"works" : 10529,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 10,
"needTime" : 10519,
"needFetch" : 0,
"isEOF" : 0,
"children" : [
{
"type" : "OR",
"works" : 10529,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 10,
"needTime" : 10519,
"needFetch" : 0,
"isEOF" : 0,
"dupsTested" : 10,
"dupsDropped" : 0,
"locsForgotten" : 0,
"matchTested_0" : 0,
"matchTested_1" : 0,
"children" : [
{
"type" : "SORT",
"works" : 10529,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 10,
"needTime" : 10518,
"needFetch" : 0,
"isEOF" : 1,
"forcedFetches" : 0,
"memUsage" : 4675,
"memLimit" : 33554432,
"children" : [
{
"type" : "FETCH",
"works" : 10518,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 1909,
"needTime" : 8608,
"needFetch" : 0,
"isEOF" : 1,
"alreadyHasObj" : 0,
"forcedFetches" : 0,
"matchTested" : 1909,
"children" : [
{
"type" : "IXSCAN",
"works" : 10518,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 10517,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 1,
"keyPattern" : "{ accountId: 1, rootId: -1.0, status: 1, type: 1 }",
"isMultiKey" : 0,
"boundsVerbose" : "field #0['accountId']: [4, 4], field #1['rootId']: [MaxKey, MinKey], field #2['status']: [MinKey, MaxKey], field #3['type']: [MinKey, MaxKey]",
"yieldMovedCursor" : 0,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0,
"keysExamined" : 10517,
"children" : [ ]
}
]
}
]
},
{
"type" : "SORT",
"works" : 0,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 0,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 0,
"forcedFetches" : 0,
"memUsage" : 0,
"memLimit" : 33554432,
"children" : [
{
"type" : "FETCH",
"works" : 0,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 0,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 0,
"alreadyHasObj" : 0,
"forcedFetches" : 0,
"matchTested" : 0,
"children" : [
{
"type" : "IXSCAN",
"works" : 0,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 0,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 0,
"keyPattern" : "{}",
"isMultiKey" : 0,
"boundsVerbose" : "field #0['accountId']: [4, 4], field #1['rootId']: [MaxKey, MinKey], field #2['status']: [MinKey, MaxKey], field #3['type']: [MinKey, MaxKey]",
"yieldMovedCursor" : 0,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0,
"keysExamined" : 0,
"children" : [ ]
}
]
}
]
}
]
}
]
}
}
在您的 Shell 查询中,您在 $or
语句的 $lt
中使用了 NumberLong(4514185)
。但是在您的 Java 查询中,您使用的是 andDB.append("$lt", 4514185);
这是一个 Integer
,因此您的 Java 查询需要从 Integer 到 Long 的类型转换。尝试在您的号码后使用 andDB.append("$lt", 4514185L);
和 L
来创建长查询。 accountId
也应该是 Long
.
在 wdberkeley 的提示下,我对索引进行了一些关注。我不明白 mongodb 如何选择索引,但在我添加另一个索引后,来自 java 代码的查询选择了正确的索引。即使我删除了后来添加的索引,它仍然使用正确的索引。所以如果查询没有使用我们想要的索引,我们应该使用提示来分配我们想要的索引。
我添加的索引:
ensureIndex({"accountId" : -1,"type" : 1,"status" : 1},{"name" : "idx_ats"});
我有一个 mongo 查询,它花费的时间与 java 代码和 shell 不同。 Java 代码如下,
mongo服务器版本是v2.6.5,v2.4.8版本没有问题
DBObject obj = new BasicDBObject();
obj.put("accountId",accountId);
List<DBObject> listOr = new ArrayList<DBObject>();
listOr.add(new BasicDBObject("status", 11));
listOr.add(new BasicDBObject("status", 12));
obj.put("$or", listOr);
BasicDBObject andDB = new BasicDBObject();
andDB.append("$gt", 0);
andDB.append("$lt",4514185);
obj.put("currBoardId",andDB);
DBCursor cur = null;
cur = coll.find(obj,new BasicDBObject("currBoardId",1)).sort(new BasicDBObject("commentId",-1)).limit(10);
当我 运行 代码时,我可以从配置文件集合中获取慢查询记录。它显示 "nscanned" : 1566031 和 "millis" : 4724 .
> db.system.profile.find().sort({$natural:-1}).limit(10);
{ "op" : "query", "ns" : "l_comment.comment", "query" : { "$query" : { "accountId" : NumberLong(4), "$or" : [ { "status" : 11 }, { "status" : 12 } ], "currBoardId" : { "$gt" : 0, "$lt" : NumberLong(4514185) } }, "$orderby" : { "commentId" : -1 } }, "cursorid" : 220355902849, "ntoreturn" : 10, "ntoskip" : 0, "nscanned" : 1566031, "nscannedObjects" : 1566031, "keyUpdates" : 0, "numYield" : 5, "lockStats" : { "timeLockedMicros" : { "r" : NumberLong(8921271), "w" : NumberLong(0) }, "timeAcquiringMicros" : { "r" : NumberLong(14), "w" : NumberLong(2) } }, "nreturned" : 10, "responseLength" : 410, "millis" : 4724, "execStats" : { "type" : "PROJECTION", "works" : 1566031, "yields" : 12234, "unyields" : 12234, "invalidates" : 0, "advanced" : 10, "needTime" : 0, "needFetch" : 0, "isEOF" : 0, "children" : [ { "type" : "FETCH", "works" : 1566031, "yields" : 12234, "unyields" : 12234, "invalidates" : 0, "advanced" : 10, "needTime" : 1566021, "needFetch" : 0, "isEOF" : 0, "alreadyHasObj" : 0, "forcedFetches" : 0, "matchTested" : 10, "children" : [ { "type" : "IXSCAN", "works" : 1566031, "yields" : 12234, "unyields" : 12234, "invalidates" : 0, "advanced" : 1566031, "needTime" : 0, "needFetch" : 0, "isEOF" : 0, "keyPattern" : "{ commentId: -1.0 }", "isMultiKey" : 0, "boundsVerbose" : "field #0['commentId']: [MaxKey, MinKey]", "yieldMovedCursor" : 0, "dupsTested" : 0, "dupsDropped" : 0, "seenInvalidated" : 0, "matchTested" : 0, "keysExamined" : 1566031, "children" : [ ] } ] } ] }, "ts" : ISODate("2015-02-10T08:51:16.195Z"), "client" : "192.168.66.103", "allUsers" : [ ], "user" : "" }
但是当我 运行 来自 shell 的查询时,它 returns 很快。
db.comment.find({ "accountId" : NumberLong(4), "$or" : [ { "status" : 11 }, { "status" : 12 } ], "currBoardId" : { "$gt" : 0, "$lt" : NumberLong(4514185) }}).sort({commentId:-1}).limit(10)
下面是解释的输出。它显示查询扫描 10517 条记录并使用 109 毫秒。 为什么会这样,我该如何改进代码?
感谢任何提示和帮助。
{
"clauses" : [
{
"cursor" : "BtreeCursor idx_atst",
"isMultiKey" : false,
"n" : 10,
"nscannedObjects" : 10517,
"nscanned" : 10517,
"scanAndOrder" : true,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"accountId" : [
[
NumberLong(4),
NumberLong(4)
]
],
"rootId" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"status" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"type" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor ",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"scanAndOrder" : true,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"accountId" : [
[
NumberLong(4),
NumberLong(4)
]
],
"rootId" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"status" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"type" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}
],
"cursor" : "QueryOptimizerCursor",
"n" : 10,
"nscannedObjects" : 10517,
"nscanned" : 10517,
"nscannedObjectsAllPlans" : 31574,
"nscannedAllPlans" : 31574,
"scanAndOrder" : false,
"nYields" : 246,
"nChunkSkips" : 0,
"millis" : 109,
"server" : "app-sz-2-3.sz.chosk.net:27017",
"filterSet" : false,
"stats" : {
"type" : "KEEP_MUTATIONS",
"works" : 10529,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 10,
"needTime" : 10519,
"needFetch" : 0,
"isEOF" : 0,
"children" : [
{
"type" : "OR",
"works" : 10529,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 10,
"needTime" : 10519,
"needFetch" : 0,
"isEOF" : 0,
"dupsTested" : 10,
"dupsDropped" : 0,
"locsForgotten" : 0,
"matchTested_0" : 0,
"matchTested_1" : 0,
"children" : [
{
"type" : "SORT",
"works" : 10529,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 10,
"needTime" : 10518,
"needFetch" : 0,
"isEOF" : 1,
"forcedFetches" : 0,
"memUsage" : 4675,
"memLimit" : 33554432,
"children" : [
{
"type" : "FETCH",
"works" : 10518,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 1909,
"needTime" : 8608,
"needFetch" : 0,
"isEOF" : 1,
"alreadyHasObj" : 0,
"forcedFetches" : 0,
"matchTested" : 1909,
"children" : [
{
"type" : "IXSCAN",
"works" : 10518,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 10517,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 1,
"keyPattern" : "{ accountId: 1, rootId: -1.0, status: 1, type: 1 }",
"isMultiKey" : 0,
"boundsVerbose" : "field #0['accountId']: [4, 4], field #1['rootId']: [MaxKey, MinKey], field #2['status']: [MinKey, MaxKey], field #3['type']: [MinKey, MaxKey]",
"yieldMovedCursor" : 0,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0,
"keysExamined" : 10517,
"children" : [ ]
}
]
}
]
},
{
"type" : "SORT",
"works" : 0,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 0,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 0,
"forcedFetches" : 0,
"memUsage" : 0,
"memLimit" : 33554432,
"children" : [
{
"type" : "FETCH",
"works" : 0,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 0,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 0,
"alreadyHasObj" : 0,
"forcedFetches" : 0,
"matchTested" : 0,
"children" : [
{
"type" : "IXSCAN",
"works" : 0,
"yields" : 246,
"unyields" : 246,
"invalidates" : 0,
"advanced" : 0,
"needTime" : 0,
"needFetch" : 0,
"isEOF" : 0,
"keyPattern" : "{}",
"isMultiKey" : 0,
"boundsVerbose" : "field #0['accountId']: [4, 4], field #1['rootId']: [MaxKey, MinKey], field #2['status']: [MinKey, MaxKey], field #3['type']: [MinKey, MaxKey]",
"yieldMovedCursor" : 0,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0,
"keysExamined" : 0,
"children" : [ ]
}
]
}
]
}
]
}
]
}
}
在您的 Shell 查询中,您在 $or
语句的 $lt
中使用了 NumberLong(4514185)
。但是在您的 Java 查询中,您使用的是 andDB.append("$lt", 4514185);
这是一个 Integer
,因此您的 Java 查询需要从 Integer 到 Long 的类型转换。尝试在您的号码后使用 andDB.append("$lt", 4514185L);
和 L
来创建长查询。 accountId
也应该是 Long
.
在 wdberkeley 的提示下,我对索引进行了一些关注。我不明白 mongodb 如何选择索引,但在我添加另一个索引后,来自 java 代码的查询选择了正确的索引。即使我删除了后来添加的索引,它仍然使用正确的索引。所以如果查询没有使用我们想要的索引,我们应该使用提示来分配我们想要的索引。
我添加的索引:
ensureIndex({"accountId" : -1,"type" : 1,"status" : 1},{"name" : "idx_ats"});