4

我正在使用 mongoDB 来存储查询日志并获取有关它的一些统计信息。我存储在 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 但没办法。我哪里错了?

4

1 回答 1

5

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

一些潜在的问题:

  1. 索引:您是否使用了正确的索引?您可能应该在IsClick/Date. 这将范围放在第二位,这是正常的建议。请注意,这与索引不同Date/IsClick,顺序很重要。在您的查询上尝试 a.explain()以查看正在使用的索引。
  2. 数据大小:在某些情况下,数据过多可能会导致速度变慢。这可能是太多的文档或太多的大文档。它也可能是由于试图在一个非常大的大海捞针中找到太多的针头造成的。您要带回 252k 的数据 ( reslen) 和 12k 的文档,所以这可能不是问题。
  3. 磁盘 IO: MongoDB 使用内存映射文件,因此使用大量虚拟内存。如果您的数据多于 RAM,则获取某些文档需要“转到磁盘”。转到磁盘可能是一项非常昂贵的操作。iostat您可以使用或resmon(Windows) 之类的工具来监视磁盘活动,从而识别“进入磁盘” 。

根据个人经验,我强烈怀疑#3,可能会从#1 恶化。我将从在运行.explain()查询时观察 IO 开始。这应该会迅速缩小可能出现问题的范围。

于 2011-11-16T17:27:33.307 回答