原文地址https://bgithub.xyz/DBatUTuebingen-Teaching/didi-ws2526数据库查询性能的演进从脚本到并行优化作者Torsten Grust时间2025/26年冬季学期单位德国图宾根大学引言性能工程的起点数据库管理系统DBMS通过充分利用现代计算机架构中的CPU多线程、内存层次结构DRAM、缓存及SSD等存储设备实现了高效的数据处理。即便是最微小的性能优化在面对数百万行数据处理时也会产生显著的放大效应。本文以一个简单的查询任务为切入点逐步展示从脚本语言到手工优化的C代码再到现代DBMSDuckDB在性能上的巨大差异。该任务为读取TPC-H基准测试中的lineitem表约720MB并对第五列quantity字段求和。一、性能极限理论下限在开始优化之前作者首先测定了硬件的理论性能极限DRAM读取带宽21 GB/s→ 理论查询时间0.03sNVMe SSD5 GB/s→ 0.14sUSB-C SSD800 MB/s→ 0.90s以太网2.5 GB/s→ 0.28s这些数值是基于I/O带宽的理想情况忽略了CPU处理开销作为后续优化的参考上限。二、逐步优化从awk到多线程C1. awk脚本解释型语言awk-F|{sum $5} END {print sum}lineitem.csv查询时间1.60s吞吐量471 MB/s问题CPU成为瓶颈即使文件缓存在DRAM中也无济于事。2. Python字节码解释逐行读取、拆分、类型转换。查询时间2.75s吞吐量275 MB/s性能更低适合快速开发但不适合大规模数据处理。3. C语言 getline()使用标准C库逐行解析。查询时间0.50s吞吐量1.5 GB/s性能大幅提升但getline()和atoi()占用大量CPU58% 14%。4. C mmap()使用mmap()一次性将文件映射到内存避免逐行系统调用。冷缓存1.6s受限于磁盘I/O热缓存0.42s吞吐量1.8 GB/s问题逐字节扫描查找换行符\n成为新瓶颈占53% CPU。5. C mmap 块级换行搜索使用64位字块并行查找换行符利用位运算宏HAS_NL()。查询时间0.27s吞吐量2.8 GB/s性能与strchr()相当但代码复杂度显著上升。6. C mmap 多线程将文件按换行符划分为12个分区每个线程独立求和。查询时间0.04s吞吐量18.8 GB/s逼近DRAM带宽上限展现了多核并行处理的巨大优势。三、SQL引擎的极致DuckDB作者使用DuckDB对同一数据执行SQL查询SELECTsum(l_quantity)FROMread_csv(lineitem.csv);查询时间0.448s首次读取将数据导入DuckDB存储格式后SELECTsum(l_quantity)FROMlineitem;查询时间0.002sCPU总时间0.007s吞吐量远超所有手工实现性能来源分析列式存储只读取l_quantity列避免扫描整行。投影下推查询计划仅访问所需字段。二进制存储无需重复解析文本。并行执行自动利用多核。内存驻留数据完全加载于DRAM。四、总结性能工程的启示实现方式查询时间吞吐量awk1.60s471 MB/sPython2.75s275 MB/sC getline0.50s1.5 GB/sC mmap0.27s2.8 GB/sC mmap 线程0.04s18.8 GB/sDuckDB (SQL)0.002s20 GB/s50年过去了关系模型的查询优化依然是活跃的研究领域。即使是个人笔记本电脑也能实现每秒数GB的数据处理能力。现代DBMS的性能并非依赖“大铁器”或集群而是通过对硬件特性的深度理解和精细的性能工程实现的。