向DuckDB表批量导入大量CSV时速度持续变慢的问题排查
从SQLite迁移至DuckDB时的CSV导入性能衰减问题
我正在从SQLite迁移到DuckDB,需要将10000个CSV文件(总计约2TB,近50亿行)导入到DuckDB表中,所有CSV的格式、结构、大小完全一致。最初导入单个CSV仅需2秒,但完成一半后每个CSV耗时增至15秒,且速度还在持续变慢。我在Windows环境下用Python操作,还发现必须断开并重新连接数据库才能释放内存,而SQLite没有这个问题。
我的代码如下:
# Process Each CSV File for i, file in enumerate(csv_files, start=1): file_start_time = time.time() # Print progress message print(f"Processing file {i}/{total_files}: {file}") # Copy csv file to table query = f"COPY search_data FROM '{file}'" con.execute(query) # cleanup if i % batch_size == 0: con.close() # Disconnect from DuckDB gc.collect() # Force memory cleanup con = duckdb.connect(raw_duckdb_path)
解决方案建议
1. 配置内存限制与自动检查点
DuckDB默认会在内存中累积写操作,直到阈值才刷盘,这会导致内存占用持续上升拖慢性能。连接时可直接指定内存限制和自动检查点参数:
con = duckdb.connect(raw_duckdb_path, config={ 'memory_limit': '16GB', # 根据机器总内存调整,建议设为总内存的70% 'checkpoint_threshold': '2GB' # 累积2GB写操作自动刷盘 })
2. 批量导入多文件,避免单文件循环
DuckDB的COPY支持直接读取多个文件,无需逐个循环处理,能大幅降低IO和连接开销:
# 按批次构造文件列表,比如每1000个文件一批 batch_size = 1000 for batch_start in range(0, len(csv_files), batch_size): batch_files = csv_files[batch_start:batch_start+batch_size] file_list = ",".join([f"'{f}'" for f in batch_files]) query = f"COPY search_data FROM [{file_list}]" con.execute(query)
3. 关闭自动提交与实时统计更新
默认的自动提交和实时统计更新会在批量导入时产生额外开销,可临时关闭:
# 导入前关闭自动提交与统计更新 con.execute("PRAGMA auto_commit = false") con.execute("PRAGMA disable_statistics = true") # 执行所有导入操作后手动提交 con.execute("COMMIT") # 导入完成后恢复统计更新 con.execute("PRAGMA disable_statistics = false")
4. 优化Windows环境IO性能
- 将CSV文件存储在SSD上,避免使用HDD
- 临时关闭Windows Defender实时扫描(导入完成后恢复)
- 使用
os.scandir()获取文件列表,比os.listdir()的IO效率更高
5. 取消频繁断开重连操作
当前的批量断开重连会增加连接初始化开销,改用内存限制和自动检查点配置后,无需断开连接即可控制内存占用。
内容的提问来源于stack exchange,提问作者Nik-D
相关产品推荐
相关产品推荐

