2013-05-15 39 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操作的限制,写入日志文件也不会有严重的性能损失。