Quack vs Arrow Flight:3.5倍差距从哪来
Quack vs Arrow Flight:为什么同为列式协议,速度差 3.5 倍?
DuckDB 发布 Quack 协议时附了一张对比表:60M 行 TPC-H lineitem 表拉取,Quack 4.94 秒,Arrow Flight(via GizmoSQL)17.4 秒。很多人质疑:两者都是列式传输,为什么差这么多? 答案藏在序列化路径的设计里。
对比代码完全开源
基准测试代码在 duckdb/duckdb-quack 仓库,三个脚本:
benchmark.py:Quack 单协议性能(用 EXPLAIN ANALYZE 预热) benchmarks/benchmark-batch.py:Quack vs Postgres vs Arrow Flight 批量传输 benchmarks/benchmark-transactions.py:小事务 TPS 对比
Arrow Flight 的对比对象是 GizmoSQL(Philip Moore 的 DuckDB Arrow Flight SQL 服务端),通过 adbc_driver_flightsql 连接 grpc://localhost:31337。测试环境为 AWS m8g.2xlarge(8 vCPU、32GB RAM、最高 15Gbps),同可用区,ping 延迟约 0.28ms。
GizmoSQL 的 Philip Moore 是最早把 DuckDB 做成客户端-服务端的开发者之一——DuckDB 团队在 Quack 发布博客的致谢中专门提到了他。用他的实现作为 Arrow Flight 的对比对象,是合理的。
差距来自三层,不是一层
第一层:序列化路径(最关键)
Quack 的 MIME 类型是 application/duckdb——直接使用 DuckDB 内部的 BinarySerializer(与 WAL 相同的序列化引擎)。数据从内存里的 DataChunk 到网络字节流,不经任何中间格式。
Arrow Flight 虽然也是列式,但路径不同:DuckDB DataChunk → Arrow RecordBatch 转换 → gRPC 序列化。DuckDB 内部用德国式的 string_t(短字符串内联、长字符串指针),Arrow 用 offset buffer + data buffer。VARCHAR 字段每行都需要一次解码+重新编码。其他类型同理——DECIMAL、TIMESTAMP、LIST 的编码布局都不一样。
结果就是 Arrow Flight 路径多了一次完整的 DuckDB → Arrow → gRPC 序列化链,而 Quack 只有 DuckDB → 网络 一次。
第二层:往返次数
Quack 把查询元数据(schema、统计信息)和结果数据打包在同一个 HTTP 响应里,一次 round trip 搞定。Arrow Flight SQL 需要先 GetCatalogs → GetSchemas → GetTables 获取元数据,再 DoGet 取数据,至少两次 round trip。两机 ping 0.28ms 时差距不大,但累积效应明显。
第三层:gRPC 开销
Quack 直接跑 HTTP POST,Content-Type: application/duckdb,body 就是二进制 stream。Arrow Flight 跑在 gRPC 上——protobuf 消息包装、HTTP/2 流控、HPACK 头部压缩,每条路径都有 CPU 开销。这不是 gRPC 的问题,而是 DuckDB 场景下不需要这些抽象层。
这不是协议之争,是序列化零成本
把这三层展开,差距的根因可以概括为:Quack 没有"适配层",Arrow Flight 有。
不是说 Arrow Flight 本身慢——如果是 Arrow-native 的数据源(Parquet 直接读到 Arrow),Arrow Flight 的表现会非常好。但在 DuckDB 这个具体场景里,数据天然以 DuckDB 内部格式存在,Arrow Flight 必须承担转换成本。
这也解释了为什么 DuckDB 团队选择自建协议而非直接接入 Arrow Flight SQL:不是为了比 Arrow 快,而是为了 零转换开销。Hannes 在博客里写得很直白——他们有机会从零设计一个 2026 年的数据库协议,这是一个奢侈。
完整数据
小数据量时两者持平——序列化开销压倒了转换开销。1M 行开始拉开差距,60M 行时 3.5 倍。
对你选型意味着什么
如果你用的是 DuckDB——数据以 .duckdb 文件或 DataChunk 形式存在——Quack 是最快的方式,没有之一。序列化零成本,一行代码启动服务端。
如果你的场景是多引擎互操作——Spark 查、Polars 读、BI 工具连——Arrow Flight 更合适。Arrow 的跨语言、跨系统生态覆盖远超 DuckDB 原生格式。
两者不是替代关系,而是优化路径不同:Quack 追求 DuckDB 原生的零成本传输,Arrow Flight 追求多引擎间的标准互操作。 知道这个区别,就知道什么时候选哪个。