Python + MongoDB - 游标迭代太慢 - 未解决?

6

我有一个数据库查询,返回150,000个文档,每个文档包含三个整数字段和一个日期时间字段。以下代码尝试从游标对象创建列表。迭代游标非常慢-大约需要80秒!通过C++驱动程序执行相同操作的速度快了几个数量级-这一定是PyMongo的问题吗?

client = MongoClient()
client = MongoClient('localhost', 27017)
db = client.taq
collection_str = "mycollection"
db_collection = db[collection_str]

mylist = list(db_collection.find())

这个问题以前已经被讨论过,我尝试了许多建议。其中一个是更改默认的批处理大小。所以我尝试了以下方法:

cursor = db_collection.find()
cursor.bath_size(10000)
mylist = list(cursor)

然而,这并没有产生影响。第二个建议是检查是否安装了C扩展 - 我已经安装了它们,所以这不是问题。Mongo数据库安装在同一台机器上,因此不是网络问题 - 它从C ++正常工作...从Pymongo查询是问题所在。
既然MongoDB被营销为能够处理大数据,那么肯定有一种通过Python快速检索数据的方法吧?这个问题之前已经提出过,但我还没有找到解决方案...有人有可以解决的建议吗?在这种情况下,我正在检索150k个文档,但通常查询会检索100万个文档,所以这对我来说将是一个真正的问题。
谢谢。

你能提供一个样本文件吗?这150k个文档有多少数据?是1MB还是2.4GB?这些文档有多复杂?你可以尝试通过套接字连接而不是通过TCP连接,这样会提高性能吗?另外,为什么要转换成列表?在使用数据之前,您需要等待所有数据传输完成。除了Python之外,您还有多少RAM可用?在集合上运行touch以预热缓存是否会提高性能?最好将票据添加到https://jira.mongodb.org/browse/PYTHON,但演示用例将有助于调试。 - Ross
每个文档都非常简单,包含一个日期时间字段和三个整数值字段。我将其转换为列表,以便可以将列表传递给Pandas DataFrame的构造函数。如果忽略列表转换,如果我删除此行并只迭代游标,则仍然非常慢。RAM不是问题,此服务器上有30GB的RAM。我发布的代码足以重新创建问题。尝试迭代150k个简单文档的游标,并查看需要多长时间。 - Rob
遍历光标结果需要多长时间,但不将项目放入列表中?几乎一样吗? - WiredPrairie
1
@Rob,你的代码中没有对游标进行迭代。实际上,如果你是从列表创建DataFrame,那么你也不需要迭代。那么,你到底是什么意思? - sashkello
这个 Rob 有任何更新吗? - Ross
2个回答

0

0

我无法复制 - 我正在加载150,000份文档,并在约0.5至0.8秒内将其转换为列表。以下是timeit测试脚本的结果 - 将150,000份文档从数据库转换为列表所需的时间(以秒为单位)。

--------------------------------------------------
Default batch size
0.530369997025
--------------------------------------------------
Batch Size 1000
0.570069074631
--------------------------------------------------
Batch Size 10000
0.686305046082

这是我的测试脚本:
#!/usr/bin/env python

import timeit

def main():
    """
    Testing loading 150k documents in pymongo
    """

    setup = """
import datetime
from random import randint
from pymongo import MongoClient
connection = MongoClient()
db = connection.test_load
sample = db.sample
if db.sample.count() < 150000:
    connection.drop_database('test_load')

    # Insert 150k sample data
    for i in xrange(15000):
        sample.insert([{"date": datetime.datetime.now(),
                        "int1": randint(0, 1000000),
                        "int2": randint(0, 1000000),
                        "int4": randint(0, 1000000)} for i in xrange(10)])

"""

    stmt = """
from pymongo import MongoClient
connection = MongoClient()

db = connection.test_load
sample = db.sample

cursor = sample.find()
test = list(cursor)
assert len(test) == 150000
"""

    print "-" * 100
    print """Default batch size"""
    t = timeit.Timer(stmt=stmt, setup=setup)
    print t.timeit(1)

    stmt = """
from pymongo import MongoClient
connection = MongoClient()

db = connection.test_load
sample = db.sample

cursor = sample.find()
cursor.batch_size(1000)
test = list(cursor)
assert len(test) == 150000
"""

    print "-" * 100
    print """Batch Size 1000"""
    t = timeit.Timer(stmt=stmt, setup=setup)
    print t.timeit(1)

    stmt = """
from pymongo import MongoClient
connection = MongoClient()

db = connection.test_load
sample = db.sample

cursor = sample.find()
cursor.batch_size(10000)
test = list(cursor)
assert len(test) == 150000
"""

    print "-" * 100
    print """Batch Size 10000"""
    t = timeit.Timer(stmt=stmt, setup=setup)
    print t.timeit(1)

if __name__ == "__main__":
    main()

我很困惑你是怎么得出80秒而不是0.8秒的!我根据你的定义创建了我的样本数据 - 这与你的有多大差异?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接