Python SQLite缓存在内存中

时间:2013-05-15 18:25:27

标签: python sqlite

我使用的是Python 2.7和SQLite。我正在构建一个包含数百万行的数据库。我想偶尔写一下磁盘,这样可以提高性能。我的想法是不时只调用commit()。我已尝试使用下面的代码。中间的选择表明我们得到了一致的读数。但是,当我查看光盘时,我看到一个文件 example.db-journal 。这必须是缓存数据的位置。在这种情况下,这将在性能方面没有任何好处。有没有办法让插入物收集在内存中,然后将它们冲到光盘?有更好的方法吗?

以下是我的示例代码:

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版批量处理的第一次削减需要大约660秒才能完成50,000行。根据评论(感谢海报),我想出了以下代码:

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%的总时间,但是,记忆是不变的,这更重要。

2 个答案:

答案 0 :(得分: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这样的完整DBMS。

答案 1 :(得分:1)

在您的情况下,您正在 autocommit 模式下创建数据库连接,这意味着每次执行INSERT语句时,数据库都会启动一个事务,执行该语句并提交。所以你的commit - 在这种情况下 - 毫无意义。 See sqlite3 on python docs

但是你应该在事务中理想地插入大量行是正确的。这表示连接,它应记录日志文件中的所有传入INSERT语句,但延迟写入数据库文件,直到事务提交。即使您的执行受到I / O操作的限制,写入日志文件也不会造成严重的性能损失。