DuckDB、SQLite、Pandas 表面上都能”读个文件、跑个聚合、出个结果”,但底层架构完全不同——DuckDB 是列存 + 向量化的 OLAP 引擎,SQLite 是行存 + 单行迭代的 OLTP,Pandas 是内存 DataFrame。同一个查询在三个工具上能差 100 倍。
这篇拆解三者真实差异、性能数量级、以及什么场景该选哪个。
三者的本质定位
| 维度 | SQLite | DuckDB | Pandas |
|---|---|---|---|
| 类型 | OLTP 嵌入式数据库 | OLAP 嵌入式数据库 | 内存 DataFrame |
| 存储 | 行存 | 列存 | 内存数组 |
| 执行 | 单行迭代 | 向量化(1024 行/批) | 向量化(NumPy) |
| 并发 | 单写多读 | 单写多读 | 单进程 |
| 适合 | 事务、点查、单行更新 | 聚合、JOIN、扫表 | 行级编程、ML 集成 |
| 数据上限 | 几百 GB | 单机几 TB | 内存大小 |
最关键的一句话:SQLite 优化”插入和单行查询”,DuckDB 优化”扫几亿行后聚合”,Pandas 优化”在内存里灵活操作”。
为什么 DuckDB 聚合快 100 倍
两个独立的优化叠加:
列存:IO 量减少 30 倍
行存(SQLite / Postgres / MySQL):
- 一行的所有列连续存
SELECT col1, col2 FROM t即使只要 2 列也要读全行 100 列- 同一列数据散布在文件各处,压缩率低
列存(DuckDB / Parquet / ClickHouse):
- 一列的所有行连续存
- 只读 SELECT 涉及的列,IO 减少 N 倍
- 同列数据相似 → 字典编码 + RLE + Snappy/ZSTD 能压到行存 1/5 - 1/10
向量化:CPU 利用率提升 10 倍
传统行存执行:
for row in table:
process(row) # 每行一次函数调用
DuckDB 向量化:
for batch in table: # 1024 行/批
process_vector(batch) # SIMD 友好
- 函数调用开销摊薄
- 分支预测命中率高
- CPU 缓存友好
- SIMD 指令一次处理 8-16 个值
CPU 利用率从 10% 提升到 80%+。
实测对比
千万行 1 GB 数据,SELECT category, SUM(amount) GROUP BY category:
| 工具 | 耗时 | 倍率 |
|---|---|---|
| SQLite | 30-90 秒 | 1× |
| Pandas | 5-15 秒 | 5-10× |
| DuckDB | 0.5-2 秒 | 30-100× |
DuckDB 默认多核并行,SQLite 单线程,又是一层加成。
DuckDB vs SQLite:什么时候 SQLite 更快
SQLite 不输 DuckDB 的场景:
- 单行点查(按主键查一条记录)—— 几乎一样快
- 高频小事务插入——SQLite 写入吞吐高
- 频繁 UPDATE——DuckDB 列存对原地更新不友好
典型架构:业务系统用 SQLite 存 OLTP 数据,定期导出 Parquet 到 DuckDB 跑分析报表。让擅长事务的做事务,擅长分析的做分析。
DuckDB vs Pandas:什么时候 Pandas 不可替代
70% 的 Pandas 用法 DuckDB 更快:
| 场景 | DuckDB | Pandas |
|---|---|---|
| 10 GB CSV 聚合 | 几 GB 内存可跑 | 需要 30-50 GB 内存 |
| GROUP BY + SUM | 5-50 倍快 | - |
| 多 CSV / Parquet 合并 | read_parquet('*.parquet') 一行 | for 循环 + concat |
| JOIN 大表 | hash join + parallel | merge 单线程 |
| 复杂查询 | SQL 清晰 | 链式调用难读 |
Pandas 仍不可替代:
- 行级自定义函数——
df.apply(lambda row: ...) - 机器学习生态——sklearn / XGBoost / PyTorch 直接吃 DataFrame
- 可视化——matplotlib / seaborn / plotly 直接接 DataFrame
- 小数据交互式探索——Jupyter 里 < 100 万行
- 复杂数据清洗——大量 IF / MAP / 不规则字符串处理
最佳实践——混用:
import duckdb
# DuckDB 做重活
df = duckdb.sql("""
SELECT user_id, COUNT(*) AS cnt, SUM(amount) AS total
FROM 'orders/*.parquet'
WHERE date >= '2026-01-01'
GROUP BY user_id
""").df() # 转 DataFrame
# Pandas 做轻活 + ML
import seaborn as sns
sns.histplot(df, x='total')
把 100 GB Parquet 用 DuckDB 聚合到 10 万行 DataFrame,再用 Pandas / sklearn 训模型 / 画图。
Polars 的位置
Polars 是 Rust 写的列存 + 向量化 DataFrame 库,定位介于 Pandas 和 DuckDB 之间:
- 比 Pandas 快 5-50 倍
- 比 DuckDB 灵活(DataFrame API 不强制 SQL)
- lazy execution + 查询优化(类似 Spark)
选哪个:
- 喜欢 SQL → DuckDB
- 喜欢 DataFrame API → Polars
- 习惯 Pandas + 不想换 → 还是 Pandas(< 1 GB 数据)
DuckDB 和 Polars 经常一起用:DuckDB 读文件 + 聚合,Polars 后续转换。
DuckDB 的内存控制
默认行为:
memory_limit= 系统内存的 80%- 超限的中间结果溢写到 temp 目录(external sort + external hash)
配置项:
PRAGMA memory_limit = '4GB';
PRAGMA temp_directory = '/mnt/nvme/duckdb-tmp';
PRAGMA threads = 8;
PRAGMA preserve_insertion_order = false; -- 大数据 INSERT 用
典型内存估算:
| 操作 | 内存需求 |
|---|---|
| 简单 SELECT WHERE | 几乎 0(流式) |
| GROUP BY | unique key 数 × 行宽 |
| HASH JOIN | 较小表 × 1.5 |
| 窗口函数 | 单 partition 大小 |
| ORDER BY 大数据 | 整个数据 |
实务:
- 数据 < 内存 → 默认配置即可
- 数据 1-5 倍内存 → 配
temp_directory到 NVMe SSD - 数据 > 10 倍内存 → 分批处理或换 ClickHouse / Spark
DuckDB 不适合的场景
| 场景 | 为什么 | 推荐 |
|---|---|---|
| 高频 INSERT / UPDATE 业务库 | 单写者 + 列存不优化点更新 | SQLite / Postgres |
| 高并发查询(> 100 QPS) | 单进程吞吐有限 | ClickHouse |
| 多用户权限管理 | DuckDB 没有 | Postgres / Snowflake |
| 持续 streaming | 不是设计目标 | ClickHouse / Flink |
| 数据 > 10 TB | 单机吃力 | ClickHouse / Snowflake |
| 跨团队 / 多业务共享 | 嵌入式 | Snowflake / BigQuery |
DuckDB 的生产用途
适合的生产场景:
- 嵌入式分析——BI 工具后端,查询本地 Parquet
- 数据 pipeline 中间层——读 S3 → 转换聚合 → 写出新 Parquet
- 小到中型团队的分析仓库——< 1 TB,< 50 人,DuckDB + Parquet on S3 + dbt-duckdb
- 客户端分析——浏览器(DuckDB-Wasm)跑 ad-hoc 查询
- 机器学习特征工程——比 Pandas 快 10 倍,比 Spark 轻 100 倍
- 替代 Jupyter 里的 Pandas 大数据
MotherDuck——DuckDB 官方云托管,hybrid execution(本地 + 云混合查询),适合从单机扩展到团队协作。
选型决策树
按这个顺序判断:
负载是 OLTP(事务、单行查询、高频更新)?
是 → SQLite(嵌入式 / 单机)/ Postgres(多机)
否 → 继续
数据量 > 10 TB 或并发 > 100 QPS?
是 → ClickHouse / Snowflake
否 → 继续
需要多用户权限 / 跨团队共享?
是 → Snowflake / BigQuery
否 → 继续
主要场景是聚合 / JOIN / 扫表分析?
是 → DuckDB
否 → Pandas / Polars(行级编程为主)
实操检查清单
把现有工作流换 DuckDB 之前过一遍:
- 真实数据跑过对比,不是看 benchmark
- 业务负载是 OLAP 还是 OLTP,别用反了
- 数据规模 < 单机能力(一般 < 1 TB)
- 没有跨团队共享 / 多用户权限需求
- 已知 Pandas / sklearn / 可视化部分继续用 Pandas,DuckDB 做重活
- 大数据时配 temp_directory 到 NVMe
- 不要拿 DuckDB 做 OLTP,反过来也不要
- 不确定时先用浏览器 DuckDB-Wasm 工具跑一次看效果
DuckDB 不是 SQLite 的替代品,是补充。两者一个做事务一个做分析,配合使用最稳。