2013-08-22 211 views
2

我有一個數據庫查找查詢返回150k文檔,其中每個文檔包含三個整數字段和一個日期時間字段。以下代碼嘗試從遊標對象創建一個列表。迭代光標非常慢 - 大約80秒!通過C++驅動程序進行的相同操作速度要快幾個數量級 - PyMongo一定是個問題?Python + MongoDB - 遊標迭代太慢 - 未解決?

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萬個文檔,所以這對我來說將是一個真正的問題。

謝謝。

+0

你能提供一個樣本文檔? 150k文件有多少數據? 1 MB或2.4GB?這些文件有多複雜?你可以嘗試連接到套接字,而不是通過TCP - 這是否提高了性能?另外爲什麼要轉換爲列表?在使用之前,您需要等到所有數據都穿過電線。除了python你有多少內存?是否在集合上運行[touch](http://docs.mongodb.org/manual/reference/command/touch/)以加熱緩存可提高性能?可能最好添加一張票到https://jira.mongodb.org/browse/PYTHON,但是一個演示用例可以幫助調試 – Ross

+0

每個文檔都非常簡單,包含一個日期時間字段和三個整數值字段。我轉換爲列表,以便我可以將列表傳遞給Pandas DataFrame的構造函數。忽略列表轉換,如果我刪除這一行,只是迭代遊標,它仍然很慢。 RAM不是問題,在這臺服務器上有30GB的RAM。我發佈的代碼足以重新創建問題。嘗試迭代150k簡單文檔的光標並查看需要多長時間。 – Rob

+0

需要多長時間來遍歷遊標的結果,但不要將項目放入列表中?幾乎一樣? – WiredPrairie

回答

2

我無法複製 - 我正在加載150k文件並在〜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!我根據您的定義創建了我的示例數據 - 與您的定義有何不同?