慢 MongoDB/pymongo 查询

Slow MongoDB/pymongo query

我正在使用 python:

的 pymongo 库向 MongoDB(版本 2.6)提交一个非常简单的查询
query = {"type": "prime"}
logging.info("Querying the DB")
docs = usaspending.get_records_from_db(query)
logging.info("Done querying. Sorting the results")
docs.sort("timestamp", pymongo.ASCENDING)
logging.info("Done sorting the results, getting count")
count = docs.count(True)
logging.info("Done counting: %s records", count)
pprint(docs[0])
raise Exception("End the script right here")

get_records_from_db()函数非常简单:

def get_records_from_db(query=None):
    return db.raws.find(query, batch_size=50)

请注意,我实际上需要处理所有文档,而不仅仅是 docs[0]。我只是想以 docs[0] 为例。

当我 运行 这个查询时,我得到的输出是:

2015-01-28 10:11:05,945 Querying the DB
2015-01-28 10:11:05,946 Done querying. Sorting the results
2015-01-28 10:11:05,946 Done sorting the results, getting count
2015-01-28 10:11:06,617 Done counting: 559952 records

然而我再也没有回来docs[0]。我在 {"timestamp": 1}{"type": 1} 上有一个索引,并且查询似乎工作得相当好(因为计数返回得非常快),但我不确定为什么我从来没有取回实际文档(the docs非常小 [50K 以下])。

您永远无法取回实际文档的原因是因为 Mongo 将这些命令批量合并到一个查询中,因此您可以这样看:

find 个记录,然后 sort 个记录,然后 count 个记录。

您需要构建两个完全独立的查询:

  1. find记录,sort记录,然后给我记录
  2. count 记录

如果将它们链接起来,Mongo 会将它们链接起来并认为它们是一个命令。

当您执行这些行时,PyMongo 不会在服务器上实际工作:

query = {"type": "prime"}
docs = usaspending.get_records_from_db(query)
docs.sort("timestamp", pymongo.ASCENDING)

此时 "docs" 只是一个 PyMongo Cursor,但它没有 在服务器上执行查询。如果你在 Cursor 上 运行 "count",那么 PyMongo 在服务器上执行 "count" 命令并 returns 结果,但 Cursor 本身仍然没有被执行。

然而,当你运行这个:

docs[0]

然后为了获得第一个结果,PyMongo 运行在服务器上进行查询。查询在 "type" 上过滤并按 "timestamp" 排序,因此在 mongo shell 上尝试此操作以查看查询有什么问题:

> db.collection.find({type: "prime"}).sort({timestamp: 1}).limit(1).explain()

如果您看到非常大的 "nscanned" 或 "nscannedObjects",那就是问题所在。您可能需要一个关于类型和时间戳的复合索引(顺序很重要):

> db.collection.createIndex({type: 1, timestamp: 1})

参见 my article on compound indexes