我有一个现有的 SQLite 3 数据库文件,我需要对其进行一些广泛的计算。从文件中进行计算非常慢,而且由于文件不大(大约 10 MB),因此将其加载到内存中应该不会有任何问题。
有没有Pythonic的方法将现有文件加载到内存中以加快计算速度?
这是我为我的烧瓶应用程序编写的片段:
import sqlite3
from io import StringIO
def init_sqlite_db(app):
# Read database to tempfile
con = sqlite3.connect(app.config['SQLITE_DATABASE'])
tempfile = StringIO()
for line in con.iterdump():
tempfile.write('%s\n' % line)
con.close()
tempfile.seek(0)
# Create a database in memory and import from tempfile
app.sqlite = sqlite3.connect(":memory:")
app.sqlite.cursor().executescript(tempfile.read())
app.sqlite.commit()
app.sqlite.row_factory = sqlite3.Row
sqlite3.Connection.backup(...)
呢? “即使其他客户端正在访问 SQLite 数据库,或者同时通过同一连接访问该数据库,此方法也会对 SQLite 数据库进行备份。”可用性:SQLite 3.6.11 或更高版本。 3.7版本新功能。
import sqlite3
source = sqlite3.connect('existing_db.db')
dest = sqlite3.connect(':memory:')
source.backup(dest)
sqlite3.Connection.iterdump
“[r]返回一个迭代器,以 SQL 文本格式转储数据库。在保存内存数据库以供以后恢复时很有用。此函数提供与 sqlite3 中的 .dump
命令相同的功能壳。”
获取这样一个迭代器并将基于磁盘的数据库转储到基于内存的数据库中,然后就可以开始计算了。计算完成后,只需以相反的方式转储回磁盘即可。
首先,您应该尝试找出导致您观察到的速度缓慢的原因。你正在写表吗?您的写入是否足够大事务,以便您不会将不必要的临时结果保存到磁盘?您可以更改写入以转到临时表(使用
pragma temp_store=memory
)吗?你能和pragma synchronous=off
一起生活吗?
我不认为这个功能在Python模块中公开,但是sqlite有一个备份API,听起来正是你所要求的:一种从一个数据库复制到另一个数据库的方法(其中一个可能是内存数据库)几乎自动工作,无需任何用户可见的表枚举。 (也许APSW暴露了这一点?)
另一个选择是创建一个 ram 磁盘(如果您对环境有足够的控制)并将文件复制到那里。
如果我们必须使用Python包装器,那么没有比两遍读取和写入解决方案更好的解决方案了。 但从版本 3.7.17 开始,SQLite 可以选择使用“内存映射 I/O”直接访问磁盘内容。 SQLite mmap。 如果你想使用
mmap,你必须使用C接口,因为没有包装器提供它。 还有另一种硬件解决方案,即存储盘。然后您就拥有了方便的文件 I/O 和内存速度。
import sqlite3 as lite
from pandas.io.sql import read_sql
from sqlalchemy import create_engine
engine = create_engine('sqlite://')
c = engine.connect()
conmem = c.connection
con = lite.connect('ait.sqlite', isolation_level=None) #Here is the connection to <ait.sqlite> residing on disk
cur = con.cursor()
sqlx = 'SELECT * FROM Table'
df = read_sql(sqlx, con, coerce_float=True, params=None)
#Read SQLite table into a panda dataframe
df.to_sql(con=conmem, name='Table', if_exists='replace', flavor='sqlite')
的解决方案,当进程达到 500 MB 时,我在使用 Python 3.7 时总是遇到内存错误。只有使用 SQLite 3 的备份功能(thinwybk 提到的),我才能够加载和保存更大的 SQLite 数据库。您也可以只用三行代码来完成同样的事情,两种方式。
SQLAlchemy
与
source.backup(dest)
函数一起使用时,那么您最终可能不会将备份放入“正确的”内存数据库中。
可以使用适当的连接字符串来修复此问题:Python - 如何将 SQLAlchemy 连接到内存中的现有数据库sqlite 支持内存数据库。
:memory:
数据库名称。也许您可以打开两个数据库(一个来自文件,一个在内存中为空),将文件数据库中的所有内容迁移到内存中,然后进一步使用内存数据库进行计算。