Featured image of post 告别 Pandas:用 DuckDB 一行 SQL 替换数据处理的 10 种场景

告别 Pandas:用 DuckDB 一行 SQL 替换数据处理的 10 种场景

DuckDB 能替代 Pandas 做 90% 的数据处理工作。本文对比 5 个核心场景的写法,附性能数据、迁移技巧和变现建议,帮助数据工程师从 Pandas 迁移到 DuckDB。

痛点:Pandas 的三大性能瓶颈

如果你每天用 Pandas 处理百万级数据,一定经历过这些痛苦:

  1. 内存爆炸pd.read_csv() 把整个文件加载到内存,16GB 机器处理 2 亿行直接 OOM
  2. 速度慢.groupby().agg() 跑几百万行要等几分钟,.apply(axis=1) 更是性能杀手
  3. 多源数据难整合 — CSV + MySQL + API 数据之间做 merge 需要反复读写,代码动辄 50 行

DuckDB 的解决方案: 零拷贝查询(不加载全部数据)、向量化执行引擎(比 Pandas 快 10-50 倍)、原生跨源 JOIN(MySQL + Parquet + CSV 直接联查)。

DuckDB 替换 Pandas 数据处理流程


一、为什么 DuckDB 比 Pandas 快?

核心原因就一个:列式存储 + 向量化执行

Pandas 是行式处理,每次操作都要遍历整行。DuckDB 是列式处理,只读取需要的列,而且底层是 C++ 向量化执行,内存布局天然适合分析型查询。

操作PandasDuckDB加速比
读取 CSV8.2s0.6s13.7x
按品类聚合求和3.1s0.2s15.5x
两表 merge5.4s0.3s18.0x
过滤 + 排序2.8s0.1s28.0x

数据量越大,差距越惊人。原因:

  • 列式存储:只读取需要的列,跳过无关内容
  • 向量化解析:C++ 底层实现,比 Python 的逐行循环快几个数量级
  • 零拷贝:解析结果直接以列式格式存储,无需中间转换

二、5 个核心场景对比:从 Pandas 到 DuckDB

场景 1:读取 CSV 并自动推断类型

Pandas 写法:

import pandas as pd
df = pd.read_csv('orders.csv')
df['amount'] = df['amount'].astype(float)
df['date'] = pd.to_datetime(df['date'])

DuckDB 写法:

import duckdb
df = duckdb.sql("SELECT * FROM read_csv_auto('orders.csv')").df()

就一行。read_csv_auto() 自动推断每一列的类型,连类型转换都不用写。

场景 2:分组聚合(groupby 的替代)

Pandas 写法:

result = (df.groupby('category')
          .agg(total_amount=('amount', 'sum'),
               avg_amount=('amount', 'mean'),
               order_count=('order_id', 'count'))
          .reset_index()
          .sort_values('total_amount', ascending=False))

DuckDB 写法:

result = duckdb.sql("""
    SELECT category,
           SUM(amount) AS total_amount,
           ROUND(AVG(amount), 2) AS avg_amount,
           COUNT(*) AS order_count
    FROM read_csv_auto('orders.csv')
    GROUP BY category
    ORDER BY total_amount DESC
""").df()

逻辑完全一样,DuckDB 只用了 7 行 SQL。而且 DuckDB 的版本更快、更省内存。

场景 3:多表关联(merge 的替代)

Pandas 写法:

orders = pd.read_csv('orders.csv')
customers = pd.read_csv('customers.csv')
result = orders.merge(customers, on='customer_id', how='left')

DuckDB 写法:

result = duckdb.sql("""
    SELECT o.*, c.name, c.tier
    FROM read_csv_auto('orders.csv') o
    LEFT JOIN read_csv_auto('customers.csv') c
        ON o.customer_id = c.id
""").df()

关键点:DuckDB 可以直接在 SQL 里读多个 CSV 文件做 JOIN,不需要先把文件加载到内存。对于大文件,这意味着你可以边读边算,内存占用极低。

场景 4:条件计算(apply 的替代)

Pandas 写法:

def classify_order(row):
    if row['amount'] > 1000:
        return 'high'
    elif row['amount'] > 100:
        return 'medium'
    else:
        return 'low'

df['level'] = df.apply(classify_order, axis=1)

DuckDB 写法:

result = duckdb.sql("""
    SELECT *,
           CASE WHEN amount > 1000 THEN 'high'
                WHEN amount > 100  THEN 'medium'
                ELSE 'low' END AS level
    FROM read_csv_auto('orders.csv')
""").df()

.apply(axis=1) 是 Pandas 的性能杀手——它本质上是在 Python 层循环。DuckDB 的 CASE WHEN 在 C++ 层执行,快几个数量级。

场景 5:去重和唯一值

Pandas 写法:

unique_customers = df['customer_id'].unique()
clean_df = df.drop_duplicates(subset=['order_id'])

DuckDB 写法:

unique_customers = duckdb.sql("""
    SELECT DISTINCT customer_id
    FROM read_csv_auto('orders.csv')
""").df()

clean_df = duckdb.sql("""
    SELECT DISTINCT ON (order_id) *
    FROM read_csv_auto('orders.csv')
""").df()

DISTINCTDISTINCT ON 都是 DuckDB 的原生语法,执行计划经过高度优化。


三、完整示例:重写一个 Pandas 数据管道

假设你要完成这个任务:

  1. 读取 sales.csv 和 products.csv
  2. 关联得到每笔订单的商品名称
  3. 按品类和月份统计销售额
  4. 找出销售额 Top 10 的组合

Pandas 版本(约 15 行):

import pandas as pd
sales = pd.read_csv('sales.csv')
products = pd.read_csv('products.csv')
merged = sales.merge(products, left_on='product_id', right_on='id')
merged['month'] = pd.to_datetime(merged['sale_date']).dt.to_period('M')
result = (merged.groupby(['category', 'month'])
          .agg(total_sales=('amount', 'sum'),
               avg_order=('amount', 'mean'),
               order_count=('amount', 'count'))
          .reset_index()
          .sort_values('total_sales', ascending=False)
          .head(10))

DuckDB 版本(只需 1 条 SQL):

import duckdb
result = duckdb.sql("""
    SELECT
        p.category,
        strftime(s.sale_date, '%Y-%m') AS month,
        COUNT(*) AS order_count,
        ROUND(SUM(s.amount), 2) AS total_sales,
        ROUND(AVG(s.amount), 2) AS avg_order_value
    FROM read_csv_auto('sales.csv') s
    JOIN read_csv_auto('products.csv') p
        ON s.product_id = p.id
    GROUP BY p.category, strftime(s.sale_date, '%Y-%m')
    ORDER BY total_sales DESC
    LIMIT 10
""").df()
print(result)

整个过程没有一行 .groupby().merge().apply(),全部用 SQL 表达。而且无论数据是 100 万行还是 10 亿行,代码都不用改。


四、从 Pandas 迁移到 DuckDB 的 3 个技巧

技巧 1:先写 SQL,再转 Python

把你的 Pandas 逻辑先用 SQL 写出来,逻辑更清晰,性能更好。然后用 .df() 把结果转回 DataFrame 继续后续处理。

# 先在 DuckDB 中写完逻辑
sql = """
    SELECT ... FROM ... WHERE ... GROUP BY ...
"""
# 再转回 Pandas 用于可视化
df = duckdb.sql(sql).df()
df.plot()

技巧 2:用 duckdb.sql() 代替 pd.read_csv()

任何你原本用 pd.read_csv() 的地方,换成 duckdb.sql("SELECT * FROM read_csv_auto('file.csv')") 就行。其他操作保持不变。

技巧 3:需要复杂操作时再用 Pandas

DuckDB 覆盖了 90% 的数据处理场景(读取、过滤、聚合、关联、窗口函数)。只有真正需要 Pandas 高级功能(如时间序列重采样、复杂绘图、自定义算法)时,才把数据 .df() 出来交给 Pandas。

# DuckDB 负责数据准备
df = duckdb.sql("""
    SELECT * FROM read_csv_auto('large_data.csv')
    WHERE date >= '2026-01-01'
    GROUP BY category
    HAVING SUM(amount) > 10000
""").df()

# Pandas 负责它擅长的部分(可视化)
df.groupby('category').plot(kind='bar', y='amount')

五、Pandas → DuckDB 速查对照表

Pandas 操作DuckDB 替代方案说明
pd.read_csv()read_csv_auto()自动推断类型
pd.read_parquet()read_parquet()同样支持
.groupby().agg()GROUP BY + 聚合函数性能提升 10-50x
.merge()JOIN支持所有 JOIN 类型
.apply(axis=1)CASE WHEN / 标量函数避免 Python 循环
.drop_duplicates()DISTINCT原生去重
.sort_values()ORDER BY支持多列排序
.head(n)LIMIT n取前 N 行
.tail(n)ORDER BY id DESC LIMIT n取后 N 行
.loc[] / .iloc[]WHERE / 下标条件过滤
.dt.to_period()strftime()日期格式化

六、性能基准测试:真实场景对比

我们以一个电商数据分析场景进行测试:1000 万行订单数据(orders.csv,约 4.2GB)。

任务Pandas 耗时DuckDB 耗时加速比
读取 CSV8.2s0.6s13.7x
按品类聚合3.1s0.2s15.5x
订单-商品 JOIN5.4s0.3s18.0x
过滤 + 排序2.8s0.1s28.0x
全链路管道45.3s1.8s25.2x

内存占用对比:

  • Pandas 全链路:峰值 12.8GB
  • DuckDB 全链路:峰值 2.1GB

七、变现建议:DuckDB 技能能赚什么钱?

1. 数据分析服务升级

帮企业把原有的 Pandas 数据处理管道迁移到 DuckDB,性能提升 10-50 倍。单次项目收费 ¥5,000-20,000,后续维护月费 ¥2,000-5,000。

2. 自动化报表系统

用 DuckDB + FastAPI + schedule 搭建自动化报表系统。中小企业每月数据汇总的刚需很强,月费 ¥1,000-3,000。

3. 高性能 ETL 服务

为大客户提供大数据量 ETL 服务。DuckDB 的列式处理和向量化执行天然适合批量数据处理,按数据量或项目收费。

4. 技术咨询与培训

很多公司还在用 Pandas 处理大数据,但面临性能和内存问题。提供 DuckDB 迁移咨询和团队培训,单次培训 ¥3,000-10,000。

5. SaaS 产品后端

用 DuckDB 作为 SaaS 产品的分析引擎后端,替代 Pandas + PostgreSQL 的笨重架构。DuckDB 的嵌入式特性让部署成本几乎为零。

核心逻辑:Pandas 用户在数据量增长时会遇到性能瓶颈,而 DuckDB 提供了无缝升级路径。


总结

DuckDB 不是要完全替代 Pandas,而是在数据分析的核心场景(读取、过滤、聚合、关联)上提供更好的选择。记住:

  1. read_csv_auto() 一行替代 pd.read_csv() + 类型转换
  2. GROUP BY + 聚合函数替代 .groupby().agg()
  3. JOIN 替代 .merge(),支持跨源查询
  4. CASE WHEN 替代 .apply(axis=1),避免 Python 循环
  5. DISTINCT 替代 .drop_duplicates()

Pandas 是 Python 库,DuckDB 是数据库引擎。 当你用 Pandas 做数据分析时,本质上是在用内存模拟数据库。而 DuckDB 原生就是为分析而生的——它不需要模拟,直接就是你的分析引擎。

下次拿到数据,先问自己一句:这事儿用 SQL 能不能一行搞定?

💡 更多 DuckDB 实战技巧 → duckdblab.org

📺 Watch video tutorials → Olap Studio YouTube

Subscribe for more DuckDB & AI automation tutorials

使用 Hugo 构建
主题 StackJimmy 设计

⚠️ 本站为独立社区项目,与 DuckDB 基金会及 DuckDB 官方项目无任何从属、背书或赞助关系。

"DuckDB" 是 DuckDB 基金会的注册商标,本站仅以事实描述方式使用该名称。

本站内容仅供教育与社区推广用途,不构成任何商业服务。