慢 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
个记录。
您需要构建两个完全独立的查询:
find
记录,sort
记录,然后给我记录
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})
我正在使用 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
个记录。
您需要构建两个完全独立的查询:
find
记录,sort
记录,然后给我记录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})