如何高效将磁盘DuckDB实例加载至内存实例且不修改源数据?
问题描述
我正在开展一个项目,第一阶段会拉取原始数据并通过DuckDB完成一系列处理,最终得到若干供下游DuckDB组件调用的表。需求如下:
- 第一阶段的输出数据需持久化存储在磁盘上,且不被下游组件修改
- 下游组件需要能够创建视图和临时表
- 数据量较小足以存入内存,无需下游组件进行磁盘操作
我原本期望有类似如下的便捷解决方案:
conn = duckdb.connect("\:memory\:") conn.load_from_disk(path_to_on_disk)
但目前DuckDB并未提供这类方法。我尝试过从磁盘连接读取每张表,转换为Pandas DataFrame后再加载到内存连接中,但该方法耗时极长。
以下是这种低效方法的示例:
def load_disk_duck_to_mem_duck(path: pathlib.Path) -> duckdb.DuckDBPyConnection: """Slow and ugly!""" source_db = duckdb.connect((path / "duck.db").as_posix()) in_memory_db = duckdb.connect("\:memory\:") tables = source_db.execute("SHOW TABLES").fetchall() # 复制每张表从磁盘到内存 for table in tables: table_name = table[0] temp_df = source_db.table(table_name).df() # 从磁盘加载表并在内存数据库中创建副本 in_memory_db.from_df(temp_df).create(table_name) return in_memory_db
可行高效方案
方案1:通过ATTACH直接在内存连接中复制磁盘表
绕过Pandas的序列化/反序列化步骤,直接在DuckDB内部完成表复制,性能大幅提升:
import duckdb from pathlib import Path def load_disk_to_memory(path: Path) -> duckdb.DuckDBPyConnection: in_memory_conn = duckdb.connect(":memory:") # 挂载磁盘上的DuckDB数据库 in_memory_conn.execute(f"ATTACH '{(path / 'duck.db').as_posix()}' AS disk_db") # 获取磁盘库中的所有表 tables = in_memory_conn.execute("SHOW TABLES FROM disk_db").fetchall() # 复制每张表到内存库 for table in tables: table_name = table[0] in_memory_conn.execute(f"CREATE TABLE {table_name} AS SELECT * FROM disk_db.{table_name}") # 卸载磁盘库,避免下游误修改 in_memory_conn.execute("DETACH disk_db") return in_memory_conn
方案2:使用DUMP和LOAD命令迁移完整数据库对象
如果需要迁移包括表、视图在内的所有数据库对象,可导出磁盘库的SQL脚本后在内存库执行:
import duckdb from pathlib import Path def load_disk_to_memory(path: Path) -> duckdb.DuckDBPyConnection: disk_conn = duckdb.connect((path / 'duck.db').as_posix()) # 导出所有表结构和数据为SQL语句 dump_sql = disk_conn.execute("DUMP").fetchall() in_memory_conn = duckdb.connect(":memory:") # 执行SQL脚本在内存中重建数据库 for stmt in dump_sql: in_memory_conn.execute(stmt[0]) disk_conn.close() return in_memory_conn
方案3:只读挂载磁盘数据库(无需复制数据)
若不需要将数据完全加载到内存,仅需下游只读访问磁盘数据并允许创建内存级视图/临时表,可直接以只读模式连接磁盘库:
import duckdb from pathlib import Path def get_readonly_conn_with_temp_access(path: Path) -> duckdb.DuckDBPyConnection: # 以只读模式连接磁盘数据库,确保原始数据不被修改 conn = duckdb.connect((path / 'duck.db').as_posix(), read_only=True) # 下游可创建临时表和视图,这些对象仅存在于当前连接的内存中,不会写入磁盘 return conn
内容的提问来源于stack exchange,提问作者MHankin
相关产品推荐
相关产品推荐

