在合理的时间内使用mongoDB检索大量记录

时间:2011-11-16 15:56:58

标签: performance mongodb cursor mongodb-java

我正在使用mongoDB存储一个querylog并获取一些关于它的统计信息。 我存储在mongoDB中的对象包含查询的文本,日期, 用户,如果用户点击某些结果等等。

现在我正在尝试检索用户在某一天未点击的所有查询 用java。我的代码大概是这样的:

    DBObject query = new BasicDBObject();
    BasicDBObject keys = new BasicDBObject();
    keys.put("Query", 1);
    query.put("Date", new BasicDBObject("$gte", beginning.getTime()).append("$lte", end.getTime()));
    query.put("IsClick", false);
    ...
    DBCursor cur = mongoCollection.find(query, keys).batchSize(5000);

查询的输出包含我需要迭代的大约20k条记录。 问题是需要几分钟:(。我认为不正常。 从服务器日志中我看到:

Wed Nov 16 16:28:40 query db.QueryLogRecordImpl ntoreturn:5000 reslen:252403 nscanned:59260 { Date: { $gte: 1283292000000, $lte: 1283378399999 }, IsClick: false }  nreturned:5000 2055ms
Wed Nov 16 16:28:40 getmore db.QueryLogRecordImpl cid:4312057226672898459 ntoreturn:5000 query: { Date: { $gte: 1283292000000, $lte: 1283378399999 }, IsClick: false }  bytes:232421 nreturned:5000 170ms
Wed Nov 16 16:30:27 getmore db.QueryLogRecordImpl cid:4312057226672898459 ntoreturn:5000 query: { Date: { $gte: 1283292000000, $lte: 1283378399999 }, IsClick: false }  bytes:128015 nreturned:2661 --> 106059ms

因此,检索第一个块需要2秒,第二个0.1秒,第三个106秒!奇怪的.. 我尝试更改批量大小,在Date和IsClick上创建索引,重启机器:P但没办法。哪里我错了?

1 个答案:

答案 0 :(得分:5)

这里有几个因素会影响速度。有必要收集一些额外的数据来确定原因。

一些潜在的问题:

  1. 索引:您使用正确的索引吗?您可能应该在IsClick/Date上建立索引。这使得范围第二是正常的建议。请注意,这与Date/IsClick上的索引不同,顺序很重要。在查询中尝试.explain()以查看正在使用的索引。
  2. 数据大小:在某些情况下,数据过多会导致速度变慢。这可能是太多文档或太多大文档。它也可能是因为试图在一个非常大的干草堆里找到太多的针头。你带回了252k的数据(reslen)和12k文件,所以这可能不是问题。
  3. 磁盘IO: MongoDB使用内存映射文件,因此使用大量虚拟内存。如果您有比RAM更多的数据,那么获取某些文档需要“转到磁盘”。转向磁盘可能是一项非常昂贵的操作。您可以使用iostatresmon(Windows)等工具来识别“转到磁盘”,以监控磁盘活动。
  4. 根据个人经验,我强烈怀疑#3,可能会因为#1而恶化。我会在运行.explain()查询时开始观察IO。这应该会迅速缩小可能出现问题的范围。