ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DuckDB与MySQL性能对比:分析型查询的显著优势

DuckDB与MySQL性能对比:分析型查询的显著优势

1. 测试环境与数据集准备

在开始性能对比之前,我们需要先搭建一个公平的测试环境。本次测试使用的是一台配置为24核CPU和64GB内存的工作站,操作系统为Windows 11专业版。这样的配置足以处理我们即将测试的超大数据集。

测试使用的数据库版本分别为:

  • MySQL 8.0.12(社区版)
  • DuckDB 1.5.1

数据集方面,我们选择了股票市场数据作为测试样本,主要包含三个表:

主表:stock_daily(股票日线数据)

  • 数据量:14,150,202行
  • CSV文件大小:1.15GB
  • 表结构包含股票代码、交易日期、开盘价、最高价、最低价、收盘价等关键金融指标

维度表1:stock_base(股票基本信息)

  • 数据量:5,362行
  • 包含股票代码、名称、所属行业、市场类型等基本信息

维度表2:stock_company(上市公司信息)

  • 数据量:5,146行
  • 包含公司法人代表、注册资本、注册日期、所在城市等详细信息

提示:在实际测试中,我们同时准备了CSV和Parquet两种格式的文件,因为DuckDB可以直接查询这些文件而无需预先加载到数据库中。

2. 基础查询性能对比

2.1 简单聚合查询

我们首先测试最基本的COUNT(*)操作:

-- MySQL查询 SELECT COUNT(*) FROM stock_daily; -- 耗时:8.038秒 -- DuckDB查询CSV文件 SELECT COUNT(*) FROM 'stock_daily.csv'; -- 耗时:0.452秒

这个简单的测试已经显示出惊人的差异:DuckDB比MySQL快了近18倍。这是因为DuckDB是面向分析型查询优化的,它可以直接扫描CSV文件而不需要像MySQL那样通过存储引擎层。

2.2 分组聚合查询

接下来我们测试分组统计操作:

-- MySQL:统计每只股票的交易天数 SELECT ts_code, COUNT(*) FROM stock_daily GROUP BY ts_code; -- 耗时:2.627秒 -- DuckDB同样查询 SELECT ts_code, COUNT(*) FROM 'stock_daily.csv' GROUP BY ts_code; -- 耗时:0.478秒

在这个测试中,DuckDB仍然保持了约5.5倍的速度优势。值得注意的是,MySQL在这个查询中能够利用到ts_code上的主键索引,而DuckDB则是在无索引的情况下完成的。

2.3 排序操作

我们进一步增加排序操作:

-- MySQL:按交易天数排序 SELECT ts_code, COUNT(*) AS days FROM stock_daily GROUP BY ts_code ORDER BY days; -- 耗时:13.16秒 -- DuckDB同样查询 SELECT ts_code, COUNT(*) AS days FROM 'stock_daily.csv' GROUP BY ts_code ORDER BY days; -- 耗时:0.495秒

这个测试结果更加惊人,DuckDB比MySQL快了26倍以上。排序操作是DuckDB的强项,因为它采用了更现代的查询执行引擎,能够更好地利用现代CPU的并行计算能力。

3. 复杂查询场景对比

3.1 条件过滤与日期查询

我们测试一个典型的业务场景:查询特定日期的上涨股票数量。

-- MySQL查询 SELECT COUNT(*) AS up FROM stock_daily WHERE trade_date='2020-05-07 00:00:00' AND close > open; -- 耗时:4.194秒 -- DuckDB查询 SELECT COUNT(*) AS up FROM read_csv('stock_daily.csv', auto_detect=true) WHERE trade_date = DATE '2020-05-07' AND close > open; -- 耗时:0.511秒

在这个测试中,DuckDB保持了约8倍的速度优势。虽然MySQL在trade_date字段上有索引,但对于这种需要扫描大量数据的查询,索引的优势并不明显。

3.2 多表关联查询

真正的性能差异出现在多表关联查询中。我们测试一个需要关联两个表的查询:

-- MySQL:按行业分组统计上涨股票 SELECT b.industry, COUNT(*) AS up FROM stock_daily a LEFT JOIN stock_base b ON a.ts_code = b.ts_code WHERE a.trade_date='2020-05-07 00:00:00' AND a.close > a.open GROUP BY b.industry ORDER BY up DESC; -- 耗时:4.705秒 -- DuckDB同样查询 SELECT b.industry, COUNT(*) AS up FROM read_csv('stock_daily.csv') a LEFT JOIN read_csv('stock_base.csv') b ON a.ts_code = b.ts_code WHERE a.trade_date = DATE '2020-05-07' AND a.close > a.open GROUP BY b.industry ORDER BY up DESC; -- 耗时:0.596秒

DuckDB在这个复杂查询中仍然保持了近8倍的速度优势。值得注意的是,DuckDB是直接从CSV文件执行这个关联查询的,而MySQL需要先将数据加载到数据库中。

3.3 三表关联查询

我们进一步增加复杂度,测试一个需要关联三个表的查询:

-- MySQL查询 SELECT c.exchange, b.industry, COUNT(*) AS up FROM stock_daily a LEFT JOIN stock_base b ON a.ts_code = b.ts_code LEFT JOIN stock_company c ON a.ts_code = c.ts_code WHERE a.trade_date='2020-05-07 00:00:00' AND a.close > a.open GROUP BY c.exchange, b.industry ORDER BY up DESC; -- 耗时:4.705秒 -- DuckDB查询 SELECT c.exchange, b.industry, COUNT(*) AS up FROM read_csv('stock_daily.csv') a LEFT JOIN read_csv('stock_base.csv') b ON a.ts_code = b.ts_code LEFT JOIN read_csv('stock_company.csv') c ON a.ts_code = c.ts_code WHERE a.trade_date = DATE '2020-05-07' AND a.close > a.open GROUP BY c.exchange, b.industry ORDER BY up DESC; -- 耗时:0.883秒

即使在这个更复杂的查询中,DuckDB仍然比MySQL快了5倍以上。这展示了DuckDB在处理复杂分析查询时的强大能力。

4. 性能差异的深层次原因

4.1 架构设计差异

MySQL是一个传统的OLTP(在线事务处理)数据库,其设计重点是保证ACID特性和高并发的事务处理能力。而DuckDB是一个OLAP(在线分析处理)数据库,专门为分析型查询优化。

关键区别包括:

  • 存储格式:MySQL使用行存储,适合点查询;DuckDB默认使用列存储,适合分析查询
  • 执行引擎:MySQL使用传统的火山模型;DuckDB使用向量化执行引擎
  • 并行处理:DuckDB能更好地利用多核CPU并行执行查询

4.2 数据加载方式

在我们的测试中,DuckDB是直接从CSV文件查询的,而MySQL需要先将数据加载到数据库中。这实际上给了MySQL一个"不公平"的优势,因为预加载数据通常应该比直接查询文件更快。但测试结果显示,即使如此,DuckDB仍然大幅领先。

4.3 索引的影响

MySQL在trade_date字段上建立了索引,理论上应该加速日期过滤查询。但在我们的测试中,这个优势并不明显,因为:

  1. 即使使用索引,MySQL仍然需要访问大量数据页
  2. DuckDB的列存储格式可以跳过不相关的数据块
  3. DuckDB的向量化处理可以更高效地处理批量数据

5. 实际应用建议

5.1 何时选择DuckDB

基于测试结果,DuckDB在以下场景中表现优异:

  • 需要快速分析大量数据,特别是临时性分析
  • 数据以文件形式存在,不想经历繁琐的数据库导入过程
  • 查询涉及复杂的聚合、排序和多表关联
  • 需要在资源有限的机器上运行分析查询

5.2 何时坚持使用MySQL

MySQL仍然是以下场景的更好选择:

  • 需要高并发的OLTP操作(如电商交易系统)
  • 需要严格的ACID保证
  • 系统已经基于MySQL构建,迁移成本高
  • 需要成熟的用户权限管理和企业级功能

5.3 性能优化技巧

对于DuckDB:

  • 将频繁查询的数据转换为Parquet格式,可以获得更好的性能
  • 对经常查询的列使用适当的压缩编码
  • 考虑为常用查询创建物化视图

对于MySQL:

  • 确保为分析查询创建适当的复合索引
  • 考虑使用MySQL的分析引擎(如HeatWave)
  • 对大表进行分区可以提高查询性能

6. 测试的局限性

虽然我们的测试展示了DuckDB在分析查询上的显著优势,但需要注意以下几点:

  1. 测试场景有限:我们只测试了特定类型的分析查询,没有测试事务处理能力
  2. 硬件影响:在SSD上,两者的性能差距可能会缩小
  3. 数据规模:对于更大的数据集(TB级别),结果可能会有所不同
  4. MySQL优化:专业的DBA可能能够通过优化配置获得更好的MySQL性能

在实际项目中,选择数据库应该基于全面的需求分析,而不仅仅是原始查询速度。系统架构、团队技能、运维成本等因素都应该纳入考虑。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进