Lua 比 DuckDB 原生慢 10 倍,但为什么你还是该用?
前几篇聊了 duckdb-luajit 能读 DICOM、能扫目录、能补类型、能接私有 API——
都是"能读什么"。这篇回答一个躲不开的问题:快不快?
直接上实测(本机同一份数据、同一个 DuckDB CLI):
● ● ●
实测 1:100 万行 CSV(23.7MB)
-- A: DuckDB 原生 read_csv
SELECT count(*) FROM read_csv('/tmp/bench.csv', auto_detect=true);
-- B: luajit 纯 Lua 解析(读文件 + 逐行拆 3 列)
LOAD 'luajit';
SELECT val FROM luajit_table('<csv-parse.lua>');
read_csv | 0.044 s | |
| 0.471 s | ||
| 10.8x |
解析密集场景,Lua 确实慢 10 倍。 这是物理性的——纯 Lua 的 string.gmatch
对 C++ 的手写 SIMD 解析器。
● ● ●
实测 2:DICOM 1000 文件(真实对比)
但是——场景不同,结论完全不同。DICOM 是"IO 密集的小文件"(每文件 1.6KB,
读文件 + 遍历几个 tag),不是"解析密集的大文件"。用同 1000 个 DICOM 文件
实测 luajit 和 dicom-rs(Rust 成熟 DICOM 库,dicom-ducklink 组件内的同源逻辑):
| 17 ms | ||
| 32 ms | 纯解析 ≈17ms,与 dicom-rs 打平 | |
| 1.9x |
luajit 只慢 1.9 倍,而且那 1.9 倍里大部分是扩展加载开销——纯解析部分
和 Rust 的成熟库打平。为什么?DICOM 元数据解析的开销被文件 IO 淹没,
Lua 的解析成本根本不占主导。
● ● ●
那 WASM 组件方案(ducklink)呢?
dicom-ducklink 的 WASM 组件内跑的就是 dicom-rs——**原生 17ms × WASM 系数
(1.5-3x)+ wasmtime 实例化(每次查询毫秒级起步),估算约 30-60ms+**——
和 luajit 的 32ms 相当或略慢(组件级为估算,datalink 依赖缺失未直接实测)。
大文件/解析密集场景,WASM 的差距会拉大。
● ● ●
所以选型方法论就一句话
- 01格式有社区扩展 → 用原生
(解析密集快 10x,别折腾) - 02没有 → read_text 一条 SQL 从仓库拉 Lua 库
(毫秒级装上)
- IO 密集小文件
(DICOM/EXIF/PDF 元数据):和原生打平(1-2x) - 解析密集大文件
:慢 10x——但"能用"vs"不能用"是 0 和 1 的区别
- 01vs WASM 组件
:小文件批量相当或略快(无 wasmtime 初始化/边界)
性能叙事完整闭环:快不快取决于场景——格式有扩展用扩展;没有扩展时,
luajit 在 IO 密集场景和原生打平,在解析密集场景慢 10x 但仍是唯一可用的桥。
(完整实测代码:github.com/alitrack/labs/tree/master/duckdb/luajit-bench)