簡體   English   中英

在python中將數據庫表寫入文件的最快方法

[英]Fastest way to write database table to file in python

我正在嘗試從數據庫中提取大量數據並將其寫入csv文件。 我正在嘗試找出最快的方法是這樣做。 我發現在fetchall結果上運行writerows比下面的代碼慢40%。

with open(filename, 'a') as f:
    writer = csv.writer(f, delimiter='\t')
    cursor.execute("SELECT * FROM table")
    writer.writerow([i[0] for i in cursor.description])

    count = 0
    builder = []
    row = cursor.fetchone()
    DELIMITERS = ['\t'] * (len(row) - 1) + ['\n']
    while row:
        count += 1
        # Add row with delimiters to builder 
        builder += [str(item) for pair in zip(row, DELIMITERS) for item in pair]
        if count == 1000:
            count = 0
            f.write(''.join(builder))
            builder[:] = []
        row = cursor.fetchone()
    f.write(''.join(builder))

編輯:我正在使用的數據庫對於我正在工作的小型公司是唯一的,因此很遺憾,我無法在這方面提供很多信息。 我使用jpype連接數據庫,因為連接的唯一方法是通過jdbc驅動程序。 我正在運行cPython 2.7.5; 很想使用PyPy,但不適用於Pandas。

由於要提取大量行,因此我猶豫使用fetchall,因為擔心內存不足。 row具有可比的性能,並且在眼睛上要容易得多,所以我想我會使用它。 謝謝一群!

有了您給我們的一些支持,就很難再具體了,但是…

我已經將您的代碼包裝為一個函數,並編寫了三個替代版本:

def row():
    with open(filename, 'w') as f:
        writer = csv.writer(f, delimiter='\t')
        cursor = db.execute("SELECT * FROM mytable")
        writer.writerow([i[0] for i in cursor.description])
        for row in cursor:
            writer.writerow(row)

def rows():
    with open(filename, 'w') as f:
        writer = csv.writer(f, delimiter='\t')
        cursor = db.execute("SELECT * FROM mytable")
        writer.writerow([i[0] for i in cursor.description])
        writer.writerows(cursor)

def rowsall():
    with open(filename, 'w') as f:
        writer = csv.writer(f, delimiter='\t')
        cursor = db.execute("SELECT * FROM mytable")
        writer.writerow([i[0] for i in cursor.description])
        writer.writerows(cursor.fetchall())

請注意,最后一個是您說過嘗試的一個。

現在,我編寫了這個測試驅動程序:

def randomname():
    return ''.join(random.choice(string.ascii_lowercase) for _ in range(30))

db = sqlite3.connect(':memory:')
db.execute('CREATE TABLE mytable (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR)')
db.executemany('INSERT INTO mytable (name) VALUES (?)',
               [[randomname()] for _ in range(10000)])

filename = 'db.csv'

for f in manual, row, rows, rowsall:
    t = timeit.timeit(f, number=1)
    print('{:<10} {}'.format(f.__name__, t))

結果如下:

manual     0.055549702141433954
row        0.03852885402739048
rows       0.03992213006131351
rowsall    0.02850699401460588

因此,在我的測試中,您的代碼花費的時間幾乎是調用fetchallwriterows兩倍!

但是,當我對其他數據庫重復進行類似的測試時, rowsall速度要比manual速度快20%到15%(從不慢40%,但rowsall可快15%)…但是rowrows總是比manual速度快得多。

我認為這是因為您的自定義代碼比csv.writerows要慢得多,但是在某些數據庫中,使用fetchall而不是fetchone (或只是迭代游標)會大大降低速度。 對於內存中的sqlite3數據庫而言,這並非如此,原因是fetchallfetchone做着所有相同的工作,然后一次向您提供列表。 對於遠程數據庫, fetchone可能會執行任何操作,從獲取所有行到一次獲取緩沖區,一次到獲取一行,這可能會比fetchall慢或快得多,具體取決於您的數據。

但是對於真正有用的解釋,您必須准確地告訴我們您正在使用哪個數據庫和庫(以及哪個Python版本-CPython 3.3.2的csv模塊似乎比CPython 2.7.5和PyPy 2.1快很多。 /2.7.2似乎也比CPython 2.7.5還要快,但是任何一個都可能也可以更快地運行您的代碼……),依此類推。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM