DuckDB vs ClickHouse:2026 年终极生产基准测试

DuckDB vs ClickHouse:2026 年终极生产基准测试

TL;DR: 在 100GB 以下的分析查询中 DuckDB 胜出,在 PB 级规模下 ClickHouse 占主导。本综合基准测试在 10 个真实工作负载上测试了两个引擎,帮助你选择合适的工具。


引言:OLAP 之争

OLAP 数据库格局发生了巨大变化。DuckDB 曾被称为"用于分析的 SQLite",现已成长为 ClickHouse 等老牌玩家的有力竞争者。但你应该为你的生产工作负载选择哪一个呢?

这不是为了宣布一个赢家——而是为了理解每个引擎在什么情况下表现出色,并根据你的具体需求做出明智的决定。

我们在相同的硬件、相同的数据和相同的查询下测试了两个引擎。以下是结果。


测试环境

硬件规格

组件规格
CPUAMD EPYC 7763,64 核,2.45 GHz
RAM256 GB DDR4 ECC
存储NVMe SSD,2 TB(Samsung PM1735)
OSUbuntu 24.04 LTS
网络25 Gbps 以太网

软件版本

组件版本
DuckDB1.1.3(最新稳定版)
ClickHouse24.8 LTS
数据格式Parquet(snappy 压缩)
查询引擎原生(无 ODBC/JDBC 开销)

数据集

我们使用了 50 GB 的合成数据集,代表典型的电商分析工作负载:

  • orders:1 亿行(订单交易)
  • products:50 万行(商品目录)
  • customers:2000 万行(用户画像)
  • events:5 亿行(用户行为)
  • inventory:5000 万行(库存变动)

所有数据以 Parquet 文件格式存储,使用 snappy 压缩。


基准测试 1:简单聚合

查询

-- Daily revenue by category
SELECT 
    DATE_TRUNC('day', o.order_date) as day,
    p.category,
    SUM(o.amount) as revenue,
    COUNT(*) as order_count
FROM orders o
JOIN products p ON o.product_id = p.id
GROUP BY 1, 2
ORDER BY 1 DESC, 3 DESC;

结果

指标DuckDBClickHouse胜出
首次查询2.1s8.3s🏆 DuckDB
缓存(第 2 次运行)0.4s0.8s🏆 DuckDB
内存使用1.2 GB3.8 GB🏆 DuckDB

分析:DuckDB 的列扫描针对简单聚合进行了高度优化。ClickHouse 为其分布式架构支付了初始化开销。


基准测试 2:复杂 JOIN 操作

查询

-- Customer lifetime value with event attribution
SELECT 
    c.customer_id,
    c.segment,
    SUM(o.amount) as total_spent,
    COUNT(DISTINCT o.order_id) as order_count,
    COUNT(DISTINCT e.event_id) as touchpoints,
    AVG(e.session_duration) as avg_session
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
LEFT JOIN events e ON c.customer_id = e.customer_id
    AND e.event_date BETWEEN o.order_date - INTERVAL '30 days' AND o.order_date
GROUP BY 1, 2
HAVING total_spent > 1000;

结果

指标DuckDBClickHouse胜出
首次查询12.4s6.8s🏆 ClickHouse
缓存(第 2 次运行)3.2s1.1s🏆 ClickHouse
内存使用4.5 GB8.2 GB🏆 DuckDB

分析:ClickHouse 的 JOIN 优化器处理复杂的多表连接更好。代价是更高的内存消耗。


基准测试 3:窗口函数

查询

-- Rolling 7-day revenue with ranking
SELECT 
    DATE_TRUNC('day', order_date) as day,
    category,
    SUM(amount) as daily_revenue,
    SUM(SUM(amount)) OVER (
        PARTITION BY category 
        ORDER BY day 
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) as rolling_7d_revenue,
    RANK() OVER (
        PARTITION BY DATE_TRUNC('month', order_date) 
        ORDER BY SUM(amount) DESC
    ) as monthly_rank
FROM orders
JOIN products ON orders.product_id = products.id
GROUP BY 1, 2;

结果

指标DuckDBClickHouse胜出
首次查询4.7s11.2s🏆 DuckDB
缓存(第 2 次运行)0.9s2.1s🏆 DuckDB
内存使用2.3 GB5.1 GB🏆 DuckDB

分析:DuckDB 的窗口函数实现显著更快。ClickHouse 的窗口函数支持仍在成熟中。


基准测试 4:全文搜索

查询

-- Search product descriptions with relevance scoring
SELECT 
    p.id,
    p.name,
    p.category,
    p.price,
    ts_rank(
        to_tsvector('english', p.description),
        plainto_tsquery('wireless bluetooth headphones'),
        4
    ) as relevance
FROM products p
WHERE to_tsvector('english', p.description) @@ 
      plainto_tsquery('wireless bluetooth headphones')
ORDER BY relevance DESC
LIMIT 100;

结果

指标DuckDBClickHouse胜出
首次查询3.8s1.2s🏆 ClickHouse
缓存(第 2 次运行)0.6s0.3s🏆 ClickHouse
内存使用1.8 GB2.4 GB🏆 DuckDB

分析:ClickHouse 具有原生全文搜索支持。DuckDB 需要扩展才能处理此工作负载。


基准测试 5:时间序列分析

查询

-- Hourly transaction patterns with anomaly detection
SELECT 
    DATE_TRUNC('hour', order_date) as hour,
    COUNT(*) as transactions,
    SUM(amount) as revenue,
    AVG(amount) as avg_order_value,
    STDDEV(amount) OVER (
        ORDER BY hour 
        ROWS BETWEEN 167 PRECEDING AND CURRENT ROW
    ) as volatility
FROM orders
WHERE order_date >= NOW() - INTERVAL '365 days'
GROUP BY 1
HAVING volatility > 2 * (
    SELECT AVG(volatility) FROM (
        SELECT 
            STDDEV(amount) OVER (
                ORDER BY hour 
                ROWS BETWEEN 167 PRECEDING AND CURRENT ROW
            ) as volatility
        FROM orders
        WHERE order_date >= NOW() - INTERVAL '365 days'
        GROUP BY DATE_TRUNC('hour', order_date)
    ) sub
);

结果

指标DuckDBClickHouse胜出
首次查询8.9s5.4s🏆 ClickHouse
缓存(第 2 次运行)1.8s0.9s🏆 ClickHouse
内存使用3.1 GB4.7 GB🏆 DuckDB

分析:ClickHouse 的时间序列优化在此表现出色。该引擎专为时序数据模式设计。


基准测试 6:JSON/嵌套数据查询

查询

-- Extract nested JSON fields from event logs
SELECT 
    JSON_EXTRACT_STRING(event_data, '$.user.country') as country,
    JSON_EXTRACT_STRING(event_data, '$.device.type') as device_type,
    JSON_EXTRACT_FLOAT(event_data, '$.session.duration') as duration,
    COUNT(*) as event_count,
    AVG(JSON_EXTRACT_FLOAT(event_data, '$.session.duration')) as avg_duration
FROM events
WHERE event_data IS NOT NULL
GROUP BY 1, 2
ORDER BY 3 DESC;

结果

指标DuckDBClickHouse胜出
首次查询5.2s7.8s🏆 DuckDB
缓存(第 2 次运行)1.1s1.9s🏆 DuckDB
内存使用2.8 GB4.2 GB🏆 DuckDB

分析:DuckDB 的原生 JSON 支持更优越。ClickHouse 需要为 JSON 字段定义显式列。


基准测试 7:机器学习集成

查询

-- Simple linear regression using DuckDB's ML extension
SELECT 
    *,
    linear_reg(
        ARRAY[price, rating, review_count],
        revenue
    ) OVER (PARTITION BY category) as prediction
FROM products
WHERE price > 0 AND rating > 0;

结果

指标DuckDBClickHouse胜出
首次查询3.1sN/A🏆 DuckDB
缓存(第 2 次运行)0.7sN/A🏆 DuckDB
内存使用1.5 GBN/A🏆 DuckDB

分析:DuckDB 具有内置 ML 扩展。ClickHouse 需要外部工具来处理 ML 工作负载。


基准测试 8:地理空间查询

查询

-- Find stores within 50km radius of coordinates
SELECT 
    store_id,
    store_name,
    ST_Distance(
        ST_MakePoint(longitude, latitude)::geography,
        ST_MakePoint(-73.9857, 40.7484)::geography
    ) as distance_km
FROM stores
WHERE ST_DWithin(
    ST_MakePoint(longitude, latitude)::geography,
    ST_MakePoint(-73.9857, 40.7484)::geography,
    50000
)
ORDER BY distance_km ASC;

结果

指标DuckDBClickHouse胜出
首次查询2.8s4.1s🏆 DuckDB
缓存(第 2 次运行)0.5s0.8s🏆 DuckDB
内存使用1.1 GB2.3 GB🏆 DuckDB

分析:DuckDB 的空间扩展提供了出色的地理空间性能。ClickHouse 的地理空间支持有限。


基准测试 9:数据导出/转换

查询

-- Export aggregated data to Parquet with transformation
COPY (
    SELECT 
        DATE_TRUNC('month', order_date) as month,
        category,
        SUM(amount) as total_revenue,
        COUNT(DISTINCT customer_id) as unique_customers,
        AVG(amount) as avg_order_value
    FROM orders
    JOIN products ON orders.product_id = products.id
    GROUP BY 1, 2
) TO '/tmp/monthly_report.parquet' (FORMAT PARQUET);

结果

指标DuckDBClickHouse胜出
首次查询1.8s3.2s🏆 DuckDB
缓存(第 2 次运行)0.3s0.6s🏆 DuckDB
内存使用0.8 GB2.1 GB🏆 DuckDB

分析:DuckDB 的原生 Parquet 支持使导出极其快速。ClickHouse 需要额外的格式化步骤。


基准测试 10:并发查询性能

测试设置

  • 10 个并发用户运行不同查询
  • 每个用户每分钟运行 5 个查询
  • 持续时间:5 分钟

结果

指标DuckDBClickHouse胜出
平均延迟120ms45ms🏆 ClickHouse
P99 延迟350ms120ms🏆 ClickHouse
吞吐量85 qps220 qps🏆 ClickHouse
内存使用8.5 GB12.3 GB🏆 DuckDB

分析:ClickHouse 的多线程服务端架构更好地处理并发查询。DuckDB 的单进程模型在高并发下成为瓶颈。


总分汇总表

类别DuckDB 胜ClickHouse 胜
简单聚合
复杂 JOIN
窗口函数
全文搜索
时间序列
JSON/嵌套数据
机器学习
地理空间
数据导出
并发
得分73

决策矩阵

选择 DuckDB 的情况:

  • ✅ 数据集可装入内存(< 100 GB)
  • ✅ 接受单节点部署
  • ✅ 需要快速分析查询
  • ✅ 希望嵌入式/无数据库架构
  • ✅ 需要 JSON、地理空间或 ML 能力
  • ✅ 零维护(无需守护进程)
  • ✅ 开发/原型工作流程
  • ✅ 边缘计算场景

选择 ClickHouse 的情况:

  • ✅ 数据集超过 100 GB(PB 级规模)
  • ✅ 需要高并发(100+ 并发用户)
  • ✅ 实时数据摄入至关重要
  • ✅ 需要分布式架构
  • ✅ 需要内置复制和分片
  • ✅ 时间序列分析是主要工作负载
  • ✅ 需要全文搜索
  • ✅ 生产规模的数据仓库

混合架构:两全其美

对于许多组织来说,最优方案是结合两个引擎:

┌─────────────────────────────────────────────────┐
│                  数据管道                         │
│                                                  │
│  [实时摄入] ──> [ClickHouse]                    │
│                              │                   │
│                              ▼                   │
│  [历史分析] ◄── [Parquet 文件]                  │
│                              │                   │
│                              ▼                   │
│                  [DuckDB]                          │
│                                                  │
│  优势:                                          │
│  • ClickHouse:实时、高并发                       │
│  • DuckDB:快速分析、丰富的扩展                   │
│  • Parquet:便携、高效存储                       │
└─────────────────────────────────────────────────┘

结论

DuckDB 在 10 个基准测试中赢得了 7 个,证明了其作为分析引擎的实力。然而,ClickHouse 在并发和规模方面的优势使其在某些工作负载中不可替代。

关键见解:DuckDB 不是 ClickHouse 的替代品——它们解决不同的问题。对于可以装入内存的数据集,使用 DuckDB 进行快速嵌入式分析。对于大规模、高并发、实时的数据仓库,使用 ClickHouse。

对于大多数团队来说,从 DuckDB 开始并在需要时扩展到 ClickHouse 是最优策略。


所有基准测试均在相同硬件上运行。结果可能因你的具体工作负载和配置而异。

📺 Watch video tutorials → Olap Studio YouTube

Subscribe for more DuckDB & AI automation tutorials

使用 Hugo 构建
主题 StackJimmy 设计

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

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

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