做技术选型或者写性能评测的人,很容易在一件事上栽跟头:手里只有一个“某某数据库更快”的模糊结论,却说不清它到底在什么数据量级、什么查询模式下快,快了十倍还是两倍,以及为什么快。最近我把 MySQL 8.0 和 DuckDB 放在同一台机器上,用一份 2 亿行的超大数据集做了完整的查询速度对比,覆盖聚合、过滤、排序、关联和复杂统计几类常见场景。这篇文章不打算只丢一堆秒数,而是把测试环境怎么搭、数据集怎么构造、每条 SQL 为什么这么写、跑出来的数字背后反映了什么原理,以及哪些坑我帮你提前踩平,一层一层讲清楚。
无论你是手里攒着海量日志正准备做分析的后端工程师,还是在 MySQL 里做报表查询已经卡到怀疑人生的数据分析师,又或者单纯想搞清楚 DuckDB 到底是“玩具”还是“神器”的技术爱好者,这篇实测记录应该都能给你一些可复用的参考。先给我的结论:在单机、超大宽表、分析型查询这个前提下,DuckDB 优势非常明显,不少场景把 MySQL 甩开一两个数量级,但要说“彻底替代”,目前还言之尚早,因为 MySQL 的生态位压根不在这。
1. 测试前的核心设计思路
1.1 为什么偏偏拿 DuckDB 和 MySQL 比
先说清楚我做这个对比的动机。MySQL 是绝大多数业务系统的默认选项,大家都很熟悉,但一旦数据量起来,你会发现它跑分析类 SQL 时那种“一步一卡”的体验其实不是个别现象。而 DuckDB 是近几年在 OLAP 领域蹿升最快的嵌入式数据库,官方定位就是“分析型查询的 SQLite”,进程内运行、零配置文件、列式存储引擎,专门为聚合和分析这种活设计的。
把这两个放一起,本质上是在比“通用事务型数据库”和“专用分析型数据库”对同一份大数据的处理效率。这不是一个不平等的比较,而是两种设计哲学的一次碰撞,对实际选型非常具有参考意义。一个负责业务系统的增删改查,一个专注海量数据的统计挖掘,搞清楚它们各自的能力边界在哪里,比单纯争论谁更强有价值得多。
1.2 数据规模与场景设计:判断标准先行
很多人做性能测试很容易犯一个错误,就是随便拉几张表、塞个几百万行数据,就开始跑 SQL 然后宣布谁快谁慢。那种测试结果基本没有参考价值,因为数据量还没大到能暴露架构差异的程度。几百万行数据在两个引擎上都可能是毫秒级返回,任何噪声都可能干扰你的判断。
我这次直接生成了 2 亿行用户行为日志表,字段包含自增主键、用户 ID、事件类型、访问页面、停留时长、设备类型、创建时间等,每行大概 110 字节,表占磁盘空间约 17GB 上下,这在单机分析场景下已经属于相当有挑战的量级。判断标准也不只是“谁先跑完”这么简单,还考虑了 CPU 利用率、内存峰值、执行计划这几个维度,确保每个数字都能反推出引擎在内部做了什么。
查询场景选择上,我有意避开了那种“索引点查”类型的问题,比如 where user_id = 123 这种——那是 MySQL 的统治区,DuckDB 作为分析型引擎本来就不擅长。测试重点放在分析场景:count、avg、多维度 group by、大范围时间过滤、全表排序取 TopN、两表关联聚合、条件聚合行转列。这些都是日常报表里最容易拖垮数据库的查询类型,贴近真实痛点。
1.3 关于公平性:这是最需要较真的地方
做数据库对比,最大的质疑声永远是关于公平性的。因为测试的目的是帮助技术决策,而不是证明某种观点,所以每一个可能偏向某方的地方我都做了标注。
比如 MySQL 使用 InnoDB,缓冲池 innodb_buffer_pool_size 设置为 6GB,在 16GB 内存的机器上算比较大方;DuckDB 默认内存限制是可用内存的 80%,我也保留了默认配置,没有额外调大。再比如 MySQL 端的数据通过 LOAD DATA 导入,DuckDB 端则直接读取同一份 CSV/Parquet 文件进行查询,某种程度上 DuckDB 甚至少了一道 MySQL 必须做的数据导入步骤,如果算上导入时间,DuckDB 的优势会更大。但这道步骤在实际应用里确实也需要算成本,所以我单独记录了建表和导入耗时,下文我会拆开说。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与数据构造过程
2.1 部署方式选了最简单的路
说实话,MySQL 的安装本身并不难,真正麻烦的是各种环境变量、初始化、服务启动之类的琐碎问题,很多人第一次装就被 Shell 终端里那一堆 mysqld: Can't create/temp files 和 ERROR 2002 (HY000) 折腾得够呛。我的建议是别在裸环境里折腾,直接用 Docker 拉官方镜像,三行命令就把事情办了。
bash复制docker pull mysql:8.0
docker run --name mysql-test \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=test123456 \
-e MYSQL_DATABASE=perf_test \
-d mysql:8.0 \
--innodb-buffer-pool-size=6442450944 \
--max-connections=500
这里把 innodb_buffer_pool_size 设成 6GB,是 MySQL 性能的关键——InnoDB 的一切读取和查询都优先经过这块内存区域,太小了会导致频繁刷盘,任何一个测试场景都会被磁盘 I/O 拖慢。另外还用 --max-connections=500 防止默认连接数太少导致并发压测时直接连不上。如果手头是 Windows 或 macOS,用 Docker Desktop 也是一样的效果,不必在安装配置教程上浪费太多精力。
DuckDB 这边更简单,它就是一个嵌入式库,压根
