在Python中,我如何在连接SQLite数据库之前完全将其加载到内存中?

8
我有一个100MB的SQLite数据库文件,希望在执行SQL查询之前将其加载到内存中。在Python中是否有可能实现这一点?
谢谢。

3
不久之前发生的事情最终都会存入记忆中。要拥有一个“全部在内存中”的数据库,唯一的方法是打开一个名为“:memory:”的数据库并从外部源创建和加载表格。你想解决什么问题?是速度太慢吗?你如何知道是数据库而不是你的代码引起的问题? - S.Lott
如何将外部数据库中的表加载到内存数据库中? - relima
4个回答

12

apsw 是 SQLite 的一个替代封装器,使您能够在执行操作之前将磁盘上的数据库备份到内存中。

来自文档

###
### Backup to memory
###

# We will copy the disk database into a memory database

memcon=apsw.Connection(":memory:")

# Copy into memory
with memcon.backup("main", connection, "main") as backup:
    backup.step() # copy whole database in one go

# There will be no disk accesses for this query
for row in memcon.cursor().execute("select * from s"):
    pass

connection以上是你的磁盘数据库。


我喜欢你的解决方案,但是有一个问题,我使用了很多pysqlite的row_factory特性;而apsw似乎没有这个特性。 - relima
这真的解决了我的问题。现在我的查询快多了。 - relima
导入apsw mem_db_loader=apsw.Connection(file_sqlite_db) connection=apsw.Connection(":memory:") connection.backup("main", mem_db_loader, "main").step() cursor = connection.cursor() - relima

3
  1. 运行一个内存数据库(标准操作)
  2. 附加磁盘数据库(文件)。
  3. 重新创建表/索引并复制内容。
  4. 分离磁盘数据库(文件)

这里有一个示例(取自这里),使用 Tcl 编写(可以帮助您了解一般思路):

proc loadDB {dbhandle filename} {

    if {$filename != ""} {
        #attach persistent DB to target DB
        $dbhandle eval "ATTACH DATABASE '$filename' AS loadfrom"
        #copy each table to the target DB
        foreach {tablename} [$dbhandle eval "SELECT name FROM loadfrom.sqlite_master WHERE type = 'table'"] {
            $dbhandle eval "CREATE TABLE '$tablename' AS SELECT * FROM loadfrom.'$tablename'"
        }
        #create indizes in loaded table
        foreach {sql_exp} [$dbhandle eval "SELECT sql FROM loadfrom.sqlite_master WHERE type = 'index'"] {
            $dbhandle eval $sql_exp
        }
        #detach the source DB
        $dbhandle eval {DETACH loadfrom}
    }
}

3

如果你使用的是Linux操作系统,你可以尝试使用tmpfs,这是一种基于内存的文件系统。

使用方法非常简单:

  1. 将tmpfs挂载到一个目录。
  2. 将SQLite数据库文件复制到该目录下。
  3. 像普通的SQLite数据库文件一样打开它。

请注意,tmpfs中的任何内容都会在重启后丢失。所以,如果文件有更改,则可能需要将其复制回磁盘。


1
请注意,您可能根本不需要将数据库显式加载到SQLite的内存中。只需通过将其复制到null来预热操作系统磁盘缓存即可。
Windows: copy file.db nul:
Unix/Mac:  cp file.db /dev/null

这样做的好处是操作系统会处理内存管理,特别是在有更重要的任务出现时及时清理。


可能只是我的电脑问题,但这种技术并没有真正提高我的性能。(Win 7 x64,8GB RAM)。 - relima
它在过去的SQLite邮件列表中为许多其他人工作,特别是在机器刚启动时,因为它会预热文件系统缓存。在您的情况下,最有可能的是该文件没有出现在文件系统缓存中。(一些复制工具告诉操作系统绕过缓存,以便它们不会将其中现有的“好”内容丢弃。) - Roger Binns
1
“nul:”技巧在Win7上对我无效,但是真正的复制(到temp.db)有效。这有点烦人,因为我必须删除临时文件以防止占用过多硬盘空间,但它可以将文件放入磁盘缓存中(使第一个查询与后续查询一样快)。 - Peter Rust
在编程语言(Python)中,无论如何,您都可以在执行工作之前先虚拟读取整个文件。有没有经验来比较这种缓存预热和“:memory:”备份方法的性能? - kxr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接