MongoDB查找具有相同的速度,有和没有索引

时间:2013-07-04 08:12:39

标签: java spring mongodb spring-mvc

我使用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

2 个答案:

答案 0 :(得分:1)

您必须按此顺序为FIRSTNAMELASTNAMEEMAIL创建复合索引,并使用升序创建所有索引。

答案 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版吗?

希望这能回答你的问题。

纠正我,你觉得我可能错了,因为我有点生气。