如何在Python sqlite3中将现有的db文件加载到内存中?

时间:2010-10-03 13:55:00

标签: python performance sqlite

我有一个现有的sqlite3 db文件,我需要在其上做一些大量的计算。从文件中进行计算是非常缓慢的,因为文件不大(〜10 MB),所以将它加载到内存中应该没有问题。

是否有Pythonic方法将现有文件加载到内存中以加快计算速度?

10 个答案:

答案 0 :(得分:104)

以下是我为烧瓶应用程序编写的片段:

import sqlite3
from StringIO 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

答案 1 :(得分:16)

sqlite3.Connection.iterdump“[r] eturns迭代器以SQL文本格式转储数据库。在保存内存数据库以便以后恢复时很有用。此函数提供与.dump相同的功能命令在sqlite3 shell中。“

获取这样一个迭代器并将基于磁盘的数据库转储到基于内存的数据库中,然后就可以进行计算了。计算完成后,只需将另一种方式转回磁盘即可。

答案 2 :(得分:8)

首先,您应该尝试找出导致您观察到的缓慢的原因。你在写表吗?您的写入是否足够大transactions,以便您不会将不必要的临时结果保存到磁盘?您可以更改写入临时表(使用pragma temp_store=memory)吗?你能和pragma synchronous=off一起生活吗?

我不认为这个功能在Python模块中公开,但是sqlite有一个backup API听起来就像你要求的那样:一种从一个数据库复制到另一个数据库的方法(其中一个可以是一个内存中的数据库,它几乎可以自动工作,而无需任何用户可见的表枚举。 (也许APSW暴露了这个?)

另一个选择是创建一个ram磁盘(如果你有足够的环境控制)并在那里复制文件。

答案 3 :(得分:5)

如果我们必须使用python包装器,那么没有比两个pass,read和write解决方案更好的解决方案了。 但从版本3.7.17开始,SQLite可以选择使用内存映射I / O直接访问磁盘内容。sqlite mmap

如果你想使用mmap,你必须使用C接口,因为没有包装器提供它。

还有另一种硬件解决方案,即内存磁盘。然后你就拥有了方便的文件IO和内存速度。

答案 4 :(得分:4)

之前已经回答过,包括In python, how can I load a sqlite db completely to memory before connecting to it?

的代码示例

你没有提到操作系统,但是Windows XP的一个问题是,无论你拥有多少内存,它都默认为10MB文件缓存。 (这在系统配备64MB等的时候才有意义)。此消息有几个链接:

http://marc.info/?l=sqlite-users&m=116743785223905&w=2

答案 5 :(得分:4)

这是一种将SQLite数据库读入内存的相对简单的方法。根据您对操作数据的偏好,您可以使用Pandas数据帧或将表写入内存中的sqlite3数据库。类似地,在操作数据之后,使用相同的df.to_sqlite方法将结果存储回db表。

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')

答案 6 :(得分:3)

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)

答案 7 :(得分:0)

sqlite支持内存数据库。

在python中,你可以使用:memory:数据库名称。

也许您可以打开两个数据库(一个来自文件,一个空内存),将所有内容从文件数据库迁移到内存中,然后进一步使用内存数据库进行计算。

答案 8 :(得分:0)

有了Cenk Alti的解决方案,当进程达到500MB时,我总是遇到Python 3.7的MemoryError。只有使用sqlite3的备份功能(thinwybk提到),我才能加载和保存更大的SQLite数据库。同样,您也可以只用三行代码来完成相同的工作。

答案 9 :(得分:0)

@thinwybkCrooner 的回答都很棒。

当您与 :memory: sqlite 数据库有多个连接时,例如将 SQLAlchemy 与 source.backup(dest) 函数一起使用时,您最终可能不会将备份放入“正确”的内存数据库中。

这可以使用正确的连接字符串来修复:https://stackoverflow.com/a/65429612/1617295 并且不涉及任何黑客行为,不使用未记录的功能。