duckdb无默认数据库,需用attach加载外部文件或register注册python对象,混用同名表会导致元数据覆盖;read_parquet需显式指定schema和过滤;jupyter中应复用连接防内存泄漏;新版已支持time/list但有限制。

duckdb 连接后查不到表,register 和 attach 混用导致元数据丢失
duckdb 默认是纯内存会话,不自动加载外部文件里的表,也不是 PostgreSQL 那种“连上就有库”。常见错误是以为 connect('my.db') 就能直接 SELECT * FROM t —— 实际上除非你显式注册或附加,否则表根本不在当前连接的 catalog 里。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
attach加载整个 DuckDB 文件(含 schema、视图、函数):con.execute("ATTACH 'data.duckdb' AS ext"),之后查ext.t - 用
register把 Python 对象(如 pandas DataFrame、polars DataFrame、Arrow Table)临时挂为表:con.register("df", my_df),之后可直接SELECT * FROM df - 别在同一个连接里先
attach又用register同名表——后者会覆盖前者,且detach不影响已register的表,容易误判数据来源
用 duckdb 做 pandas 替代时,read_parquet 性能比 pandas.read_parquet 快但默认不推断 schema
duckdb 的 read_parquet 是真正下推过滤+列裁剪的,但默认行为是“只读 metadata,不 scan 数据”,所以遇到 null 类型列、嵌套结构或分区路径时,常报 Invalid Input Error: Cannot automatically determine schema。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 明确指定 schema:用
read_parquet('logs/*.parq', hive_partitioning=True)处理分区目录;用read_parquet('x.parq', columns=['a','b'], filters=[('ts', '>', '2024-01-01')])提前过滤 - 避免无脑加
use_threads=True:duckdb 默认已并行,设成False反而可能触发单线程 fallback,尤其在小文件多的场景 - 如果上游 parquet 是 pyarrow 写的且含 dictionary,duckdb 有时会 decode 失败,加
use_pandas_metadata=True可缓解
在 Jupyter 里反复运行 duckdb.connect() 导致内存泄漏和临时文件堆积
duckdb 的 connect(':memory:') 看似轻量,但每次新建连接都会初始化独立的 WAL、temp dir 和 function registry。Jupyter Cell 多次执行后,旧连接没 close,WAL 日志和临时 spill 文件(/tmp/duckdb_*)不会自动清理,最终 OOM 或磁盘占满。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 全局复用一个连接对象:定义
con = duckdb.connect(':memory:')在 notebook 最顶上,后续所有 cell 都用它 - 真要隔离 session?用
duckdb.connect(database=':memory:', read_only=True)+con.close()显式释放,别依赖 GC - 检查临时文件:运行
con.execute("PRAGMA temp_directory").fetchone(),确认路径是否可控;必要时手动PRAGMA temp_directory='/dev/shm'指向内存盘
duckdb 执行 SQL 报 Not implemented Error: Unsupported type: TIME 或 LIST
duckdb 对 Arrow 类型的支持是渐进式的,TIME、LIST、STRUCT、DECIMAL 等类型在较老版本(
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 升级到
duckdb>=0.10.2,TIME和LIST已支持基本操作(但LIST仍不支持窗口函数) - 注册 DataFrame 前先 cast:pandas 中的
timedelta64[ns]→ 改用datetime64[ns];Arrow 中的list<item: int64></item:>→ 先unnest或转成 string - 不确定类型时,用
con.execute("DESCRIBE SELECT * FROM t").fetchall()查 duckdb 实际识别的类型,别信原始 DataFrame 的dtypes
duckdb 的“嵌入式”不是指“开箱即用”,而是指“所有能力都在单个 .so/.dll 里”——但怎么把数据喂进去、在哪存中间结果、类型怎么对齐,这些都得自己搭桥。最常卡住的地方,其实是忘了它压根没有“默认数据库”这个概念。










