2013-05-15 105 views
3

我正在使用Python 2.7和SQLite。我正在構建一個數百萬行的數據庫。我只想偶爾寫出來,這會提高性能。我的想法是不時調用commit()。我已經用下面的代碼嘗試過了。中間的選擇表明我們獲得一致的讀取。但是,當我看光盤時,我看到一個文件example.db-journal。這一定是數據被緩存的地方。在這種情況下,這在性能方面沒有任何好處。是否有辦法將插入內容收集在內存中,然後將它們刷新到光盤?有一個更好的方法嗎?內存中的Python SQLite緩存

這裏是我的示例代碼:

import sqlite3 
conn = sqlite3.connect('example.db') 
c = conn.cursor() 
c.execute('CREATE TABLE if not exists stocks (date text, trans text, symbol text, qty real, price real)') 

c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
t = ('RHAT',) 
c.execute('SELECT date, symbol, trans FROM stocks WHERE symbol=?', t) 
# Here, we get 2 rows as expected. 
print c.fetchall() 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 

conn.commit() 

t = ('RHAT',) 
c.execute('SELECT date, symbol, trans FROM stocks WHERE symbol=?', t) 
# Here, we get all the rows as expected. 
print c.fetchall() 

conn.close() 

更新:

想我會放棄在任何情況下,一些代碼的更新過這個問題上運行。 我正在處理來自文本文件的超過500萬行,並需要一個位置來存儲數據以進行更多處理。我原本擁有內存中的所有數據,但內存不足。所以,我切換到SQLite的光盤緩存。我原來的在內存中版本的處理過程中,每50,000行從原始文本文件中花費約36秒。

經過測量,我在SQLite版本的批處理上花了大約500秒的時間花了660秒。根據該意見(感謝海報),我想出了下面的代碼:

self.conn = sqlite3.connect('myDB.db', isolation_level='Exclusive') 
self.cursor.execute('PRAGMA synchronous = 0') 
self.cursor.execute('PRAGMA journal_mode = OFF') 

另外,我從後我的文本文件處理1000行提交。

if lineNum % 1000 == 0: 
    self.conn.commit() 

因此,文本文件中的50,000行現在需要大約40秒。所以,我增加了11%的總時間,但是,記憶是不變的,這是更重要的。

+0

您可能會使用像redis這樣的內存存儲。 – Pramod

+2

如果您真的需要這個(措施!),您可以嘗試使用內存中的sqlite數據庫(「:memory:」),並將其內容定期轉儲到磁盤上的數據庫。 –

回答

1

首先,你確定你需要這個嗎?對於閱讀,操作系統應該緩存文件,如果你寫很多,不同步到光盤意味着你可以輕鬆地丟失數據。

如果您測量並確定這是一個瓶頸,你可以使用connect(':memory:')使用內存數據庫,並得到一個迭代器按需返回一個SQL轉儲:http://docs.python.org/2/library/sqlite3.html#sqlite3.Connection.iterdump

import sqlite3, os 

in_memory = sqlite3.connect(':memory:') 
# do stuff 

con = sqlite3.connect('existing_db.db') 
con.execute('drop table stocks') 
for line in in_memory.iterdump(): 
    con.execute(line) 

再次測量,如果你需要這個。如果您有足夠的數據,請考慮使用不同的數據存儲,例如像postgres這樣的完整數據庫。

+0

好吧,夠公平的。我沒有測量過。似乎很明顯,緩存將是正確的事情要做,直到你指出,否則。你上面寫的代碼看起來好像會按照我的要求做,但是,可能會更慢(即遍歷內存中的數據集?無論哪種方式,基於其他評論看起來是對我的。 –

+0

這更有趣思考實驗,而不是我想要的數據...... –

1

在你的情況,你正在創建自動提交模式,這意味着你每次執行INSERT語句數據庫連接,數據庫啓動一個事務,執行語句並提交。所以你的commit是 - 在這種情況下 - 沒有意義。 See sqlite3 on python docs

但是你應該正確的做法是在事務中理想地插入大量的行。這表示連接,它應該記錄日誌文件中所有傳入的INSERT語句,但是延遲寫入數據庫文件直到事務提交。即使您的執行受到I/O操作的限制,寫入日誌文件也不會有嚴重的性能損失。