我使用Spring的MongoTemplate来访问MongoDB。
final Query query = new Query(Criteria.where("_id").exists(true));
query.with(new Sort(Direction.ASC, "FIRSTNAME", "LASTNAME", "EMAIL"));
if (count > 0) {
query.limit(count);
}
query.skip(start);
query.fields().include("FIRSTNAME");
query.fields().include("LASTNAME");
query.fields().include("EMAIL");
return mongoTemplate.find(query, User.class, "users");
我在MongoDB中生成了400.000条记录。 在不使用上述书写排序行的情况下询问前25个用户时,我得到的结果不到50毫秒。
排序时间超过4秒。
然后我为FIRSTNAME,LASTNAME,EMAIL创建了索引。单个索引,而不是组合索引
mongoTemplate.indexOps("users").ensureIndex(new Index("FIRSTNAME", Order.ASCENDING));
mongoTemplate.indexOps("users").ensureIndex(new Index("LASTNAME", Order.ASCENDING));
mongoTemplate.indexOps("users").ensureIndex(new Index("EMAIL", Order.ASCENDING));
创建这些索引后,查询将再次持续4秒以上。
我的错误是什么?
- 编辑 MongoDB在控制台上写这个......
Thu Jul 04 10:10:11.442 [conn50] query mydb.users query: { query: { _id: { $exists: true } }, orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1 } } ntoreturn:25 ntoskip:0 nscanned:382424 scanAndOrder:1 keyUpdates:0 numYields: 2 locks(micros) r:6903475 nreturned:25 reslen:3669 4097ms
答案 0 :(得分:1)
您必须按此顺序为FIRSTNAME
,LASTNAME
和EMAIL
创建复合索引,并使用升序创建所有索引。
答案 1 :(得分:0)
Thu Jul 04 10:10:11.442 [conn50] query mydb.users query:
{ query: { _id: { $exists: true } }, orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1 } }
ntoreturn:25 ntoskip:0 nscanned:382424 scanAndOrder:1 keyUpdates:0 numYields: 2
locks(micros) r:6903475 nreturned:25 reslen:3669 4097ms
可能的不良迹象:
你的scanAndOrder会成真(scanAndOrder=1
),如果我错了,请纠正我。
必须返回(ntoreturn:25
)表示25个文档,但它正在扫描(nscanned:382424
)382424个文档。
索引查询,nscanned是Mongo扫描范围内的索引键数,nscannedObjects是它为获得最终结果而查看的文档数。 nscannedObjects至少包括所有返回的文档,即使Mongo只是通过查看索引确定文档肯定是匹配的。因此,您可以看到nscanned> = nscannedObjects> = n always。
问题背景:
案例1 :在不使用上述书面排序行的情况下要求前25位用户时,我会在不到50毫秒的时间内得到结果。
案例2:排序时间超过4秒。
query.with(new Sort(Direction.ASC, "FIRSTNAME", "LASTNAME", "EMAIL"));
在这种情况下,没有索引:所以它就像这里提到的那样:
这意味着MongoDB必须将所有结果批量存储在内存中,对它们进行排序,然后返回它们。信息比比皆是。首先,它会占用服务器上的RAM和CPU。此外,Mongo不是批量传输我的结果,而是立即将它们全部转储到网络上,对我的应用服务器上的RAM造成负担。最后,Mongo对将在内存中排序的数据强制实施32MB的限制。
案例3:为FIRSTNAME,LASTNAME,EMAIL创建了索引。单个索引,而不是组合索引
我猜它仍然没有从索引中获取数据。您必须根据排序顺序
调整索引排序字段(升序/降序仅在有多个排序字段时才有意义)
Add sort fields to the index in the same order and direction as your query's sort
有关详细信息,请检查此项 http://emptysqua.re/blog/optimizing-mongodb-compound-indexes/
可能答案:
在查询orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1 } }
中,排序顺序与您在以下位置指定的顺序不同:
mongoTemplate.indexOps("users").ensureIndex(new Index("FIRSTNAME", Order.ASCENDING));
mongoTemplate.indexOps("users").ensureIndex(new Index("LASTNAME", Order.ASCENDING));
mongoTemplate.indexOps("users").ensureIndex(new Index("EMAIL", Order.ASCENDING));
我猜Spring API可能不会保留订单: https://jira.springsource.org/browse/DATAMONGO-177
当我尝试对多个字段进行排序时,不会保留字段的顺序。 Sort类使用的是HashMap而不是LinkedHashMap,因此无法保证返回它们的顺序。
你能提一下spring jar版吗?
希望这能回答你的问题。
纠正我,你觉得我可能错了,因为我有点生气。