我使用的是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%的总时间,但是,记忆是不变的,这更重要。
答案 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操作的限制,写入日志文件也不会造成严重的性能损失。