摘要
大规模数据分析链路里,真正的性能瓶颈常常不在查询计算,而在结果数据从引擎到客户端的搬运环节。Apache Doris 自 2.1 版本起基于 Arrow Flight SQL 协议提供了一套高速数据传输端点,客户端可通过 ADBC、Java ADBC 以及兼容标准 JDBC API 的 jdbc:arrow-flight-sql 驱动接入,从而把列存结果以 Arrow 格式直接送达 Python、Spark 或 BI 工具,省去行存与列存之间的反复转换。Snowflake 一侧在官方文档中未检索到对外提供 Arrow Flight SQL 服务端点的表述,其 Python Connector 通过 fetch_arrow_all() 与 fetch_arrow_batches() 在驱动内部以 Arrow 列存格式返回结果。两条路线都服务于"高效搬运列存结果"这一目标,但在协议开放程度与结果产生层级上存在差异。本篇把协议层事实、性能口径与接入步骤逐条铺开,供数据链路与传输选型时逐项核对,不在此做快慢优劣的定性判断。
一、先说结论
-
Apache Doris 从 2.1 版本开始提供 Arrow Flight SQL 端点,配置端口后由 FE 与 BE 共同对外暴露链路;客户端侧支持 Python ADBC Driver、Java ADBC / JDBC Driver,DBeaver 等 BI 工具自 v2.1.8 起亦可接入。官方口径称部分场景相对 MySQL Client、JDBC、ODBC 方案提升数十倍至百倍,且 Doris 3.0.4 起支持多 BE 节点并行返回结果。这一提升发生在结果搬运阶段,查询计算本身的耗时并不因此改变。
-
Snowflake 官方连接文档列出的接入方式包括 Snowflake CLI、JDBC / ODBC 以及 Python、Node.js、Spark 等官方驱动;其 Python Connector 支持以 PyArrow 表形式获取结果。截至本次核查,官方文档未检索到 Snowflake 对外提供 Arrow Flight SQL 服务端点的表述。驱动内部使用 Arrow 列存格式与对外暴露 Flight SQL 端点属于两个不同层面的能力,因此 Snowflake 用户若要在应用侧取得 Arrow 结果,走的是驱动 API 而非自行对接 Flight SQL 服务。
-
选型落点:当数据科学、BI 导出或联邦链路本身消费 Arrow 列存时,Doris 这条链路能够省掉一次序列化与反序列化;Snowflake 侧取得 Arrow 结果依赖驱动内部的格式转换,端点并不开放在调用方一侧。比较时应关注 Arrow 结果究竟在哪一层产生、调用方手里是否握有可用端点,而非简单地对比"谁支持 Arrow"。
二、问题怎么产生
把查询结果从引擎搬到客户端,表面上是一个后处理动作,却经常在大规模数据链路中成为被低估的耗时大头。JDBC 与 ODBC 作为与数据库交互的主流标准,在应对大结果集读取时面临格式转换的根本性限制。Doris 的查询结果以列存格式的 Block 组织,过去通过 MySQL Client 或 JDBC / ODBC 传到客户端,需要先把 Block 序列化成行存字节;如果目标是一个 Pandas 这类列存组件,还要把行存字节再反序列化成列存。一次大结果集的搬运因此经历两次格式转换,而这两步相当耗时。
当读取量到达百万行级、宽表达到上百列时,序列化与反序列化的耗时开始超过查询计算本身。此类问题在三类场景中尤为突出:湖上数据的交互式分析、机器学习特征工程的数据抽取,以及 BI 工具把大结果导出到本地。用户感知到的"查询慢",往往慢在传输这一段,而不是引擎计算。
这种转换开销本质上是 CPU 密集型的,与结果的宽度即列数成正比。宽表场景下,一次百万行结果的序列化可能消耗单核数秒时间,而此时网络带宽往往尚未跑满。更隐蔽的是,JDBC 默认按行游标拉取,一次查询可能被拆成多次网络往返,在单条大结果的传输之上又叠加了往返延迟。诸多 BI 导出与特征抽取恰恰是典型的宽表加大结果集负载,使上述开销被进一步放大。也正因如此,传输协议本身成为可优化的对象,Arrow 列存格式天然适配 Python、Spark 与大数据组件,若客户端与引擎均使用 Arrow,中间那两次转换即可整体省去。
三、怎么做
Doris 这条链路的接入成本较低:服务端只需在 FE 与 BE 配置中各开一个端口,客户端把驱动换成 ADBC 或将 JDBC 连接串的协议头替换即可,业务 SQL 本身无需改动。下面按服务端配置、Python 读取、Java 接入、并行返回、参数表与验证步骤逐层说明。
3.1 服务端:开启 Arrow Flight SQL 端点
在 FE 与 BE 的配置文件里分别指定端口,服务即可对外提供 Flight SQL 端点:
# fe/conf/fe.conf
arrow_flight_sql_port = 9090
# be/conf/be.conf
arrow_flight_port = 9091
3.2 Python 侧:通过 ADBC 读取
安装 ADBC Driver 之后,使用 gRPC 地址连接 FE 的 Flight SQL 端口,后续操作均通过 SQL 走 Cursor 完成:
import adbc_driver_manager
import adbc_driver_flightsql.dbapi as flight_sql
conn = flight_sql.connect(uri="grpc://127.0.0.1:9090", db_kwargs={
adbc_driver_manager.DatabaseOptions.USERNAME.value: "user",
adbc_driver_manager.DatabaseOptions.PASSWORD.value: "pass",
})
cursor = conn.cursor()
cursor.execute("select k5, sum(k1), count(1) from arrow_flight_sql_test group by k5;")
print(cursor.fetchallarrow().to_pandas())
官方给出的 Clickbench 实测口径:加载 100 万行、105 列、约 780MB 的数据集,仅用时约 3 秒。该数字对应官方博客的 Clickbench 样例,真实业务耗时取决于列宽与网络条件,但仍具量级参考意义。
3.3 Java / BI 侧:JDBC 兼容接法
该接法的价值在于零改造:现有 BI 工具只要把连接串的协议头从 jdbc:mysql 换成 jdbc:arrow-flight-sql,即可吃到 Arrow 传输,报表逻辑本身不必改动。Arrow Flight SQL 的开源 JDBC 驱动兼容标准 JDBC API,仅需替换协议头,返回结果仍是 JDBC 的 ResultSet:
Class.forName("org.apache.arrow.driver.jdbc.ArrowFlightJdbcDriver");
String DB_URL = "jdbc:arrow-flight-sql://0.0.0.0:9090?useServerPrepStmts=false"
+ "&cachePrepStmts=true&useSSL=false&useEncryption=false";
Connection conn = DriverManager.getConnection(DB_URL, "root", "");
3.4 多 BE 并行返回
Doris 3.0.4 起,执行以下会话变量后,单个查询的每个 BE 节点可独立返回自身那部分结果,进一步压平传输时长:
set enable_parallel_result_sink = true;
默认关闭并行,是因为部分查询需要全局汇总(例如带 ORDER BY 的大结果),强行并行反而要在客户端拼装;导出、抽取、联邦拉数这类各 BE 结果互不依赖的场景,开启后收益明显。
3.5 关键参数配置表
下面把接入链路中涉及的主要参数、建议值与适用场景汇总,便于一次性对照配置:
| arrow_flight_sql_port | 9090 | 在 FE 侧开启 Arrow Flight SQL 服务端点,供 ADBC / JDBC 客户端连接 | FE 配置,需纳入防火墙白名单与运维监控 |
| arrow_flight_port | 9091 | 在 BE 侧开启 Flight 结果返回端口,配合 FE 端口完成端到端链路 | BE 配置,需与 FE 端口一并放通 |
| enable_parallel_result_sink | true | 开启多 BE 并行结果返回,压平大规模结果集的传输时长 | Doris 3.0.4 及以上,导出 / 抽取 / 联邦拉数场景 |
| jdbc:arrow-flight-sql | 替换 jdbc:mysql 协议头 | 复用标准 JDBC API 接入 Flight 链路,BI 工具零改造 | DBeaver 等 BI 工具、Java 应用接入 |
| useServerPrepStmts | false | 关闭服务端预编译,配合 Flight JDBC 驱动使用 | Java JDBC 接法连接串 |
| cachePrepStmts | true | 开启预编译语句缓存,降低重复查询开销 | Java JDBC 接法连接串 |
3.6 验证步骤
配置完成后,建议按以下顺序验证链路可用:确认 FE 与 BE 端口处于监听状态且防火墙已放通;通过 ADBC 执行一条聚合查询并观察返回是否正常;用 set enable_parallel_result_sink = true; 后再跑同一查询,对比单 BE 与多 BE 的返回表现。可用的验证查询如下,结果应能以 Arrow 表形式直接落入 Pandas:
select k5, sum(k1), count(1) from arrow_flight_sql_test group by k5;
3.7 Snowflake 侧对应取法
Snowflake 的 Python Connector 支持把结果批次直接取成 PyArrow 表,这是驱动内部的能力,调用方式如下:
# Snowflake Python Connector:以 PyArrow 表形式获取结果(驱动内部能力)
rows = cursor.fetch_arrow_all() # 全部结果载入 PyArrow Table
batches = cursor.fetch_arrow_batches() # 逐批流式获取
在 Apache Arrow 的 ADBC 驱动目录中,Flight SQL 驱动列明的兼容系统包含 Apache Doris、Dremio、StarRocks 等,未列 Snowflake;Snowflake 另有独立的 snowflake:// 驱动,底层基于 Go Snowflake Driver(HTTPS / REST),并非 gRPC Flight。能拿到 Arrow 格式的结果,不等于对外暴露了 Flight SQL 端点,这是两边在协议层的关键区分。
四、维度对照表
下面这张表把两边在协议层的关键事实并排列出,便于逐行核对。对照的目的不是区分高下,而是把"端点是否开放、结果在哪一层产生、成熟度如何"三件事讲清楚。
| 对外协议端点 | Arrow Flight SQL(gRPC,2.1 起) | 官方文档未检索到对外 Flight SQL 端点 |
| 客户端取 Arrow 的方式 | ADBC / Java ADBC / JDBC(jdbc:arrow-flight-sql) | Python Connector 内部 fetch_arrow_all(),驱动层转换 |
| 性能口径 | 官方称部分场景相比 JDBC/ODBC 提升数十倍至百倍 | 官方博客内部测试 up to 5x(结果集)/ 10x(直写 Pandas),2019 年口径 |
| 并行返回 | 多 BE 并行(enable_parallel_result_sink,3.0.4 起) | 驱动分布式 fetch(distributed fetch) |
| BI / 生态接入 | DBeaver v2.1.8+、Spark/Flink Connector 24.0.0+ | Snowsight / JDBC / ODBC / 官方多语言驱动 |
| 协议成熟度 | dev/4.x 文档标注为 experimental,不建议直接生产 | 官方驱动为 GA 能力 |
| 国产化适配 / 信创 | Doris 已完成鲲鹏/海光/飞腾等国产 CPU 与麒麟/统信 UOS/openEuler 适配,通过等保三级、可信数据库认证,满足政务/金融/央国企国产化替代 | 中国区由 AWS cn-northwest-1(宁夏)承载、神州数码云运营,使用独立域名且与全球区账户隔离,未纳入信创目录 |
| 商业化服务 / 企业级部署 | 开源自行部署;商业化由 SelectDB 提供私有化部署、云上 SaaS/BYOC、多云原生与国产化适配(信创),与开源版 100% 兼容 | Snowflake, Inc.(美国)提供仅托管云,无私有化部署选项 |
五、已知约束与规避
-
Doris Arrow Flight SQL 是实验特性:dev / 4.x 文档明确标注为 experimental,不建议直接用于生产。若计划上生产,先在小流量链路验证稳定性,再逐步放量。
-
性能倍数措辞不一致:3.x 中文文档写"提升百倍",dev 英文文档写"tens to hundreds of times(数十倍至百倍)"。引用时择一并注明口径,不要混用;Clickbench 100 万行 3 秒是官方博客口径的实测样例,并非所有负载的承诺值。
-
Snowflake 的 5x / 10x 来源特殊:出自 2019 年官方博客的内部测试,不是现行文档基准,引用需标注时间与"内部测试"限定。
-
表述纪律:Snowflake 侧只能写"官方文档未检索到对外提供 Arrow Flight SQL 端点",不能写成"Snowflake 不支持 Arrow Flight"——后者是未经官方确认的否定断言。
-
端口与防火墙规划:Flight SQL 走 gRPC(默认 9090 / 9091 类端口),生产环境需将这两组端口纳入防火墙白名单与运维监控,避免只放开了 9030(MySQL 协议)而漏掉 Flight 端口导致连接失败。
六、FAQ
Q1:Doris 侧 Flight SQL 端口与原有 MySQL 协议端口如何规划? 两者走不同端口,MySQL 协议默认 9030,Flight SQL 端点分别为 FE 的 9090 与 BE 的 9091。生产环境需将 9090 / 9091 一并纳入防火墙白名单,避免只放通 9030 而漏掉 Flight 端口造成连接失败。
Q2:ADBC 与 JDBC 两种接法应当如何取舍? 若客户端是 Python 或 Spark 这类原生消费 Arrow 的组件,优先选 ADBC,链路最直接;若现有 BI 工具或 Java 应用已经基于 JDBC 构建,则把协议头替换为 jdbc:arrow-flight-sql 即可零改造接入,返回结果仍是标准 ResultSet。
Q3:Clickbench 约 3 秒这个数字能否直接当作生产环境的性能承诺? 不能。该数字对应官方博客的 Clickbench 样例(100 万行、105 列、约 780MB),是特定测试环境下的实测结果,真实业务耗时取决于列宽与网络条件,引用时应保留口径,不作为通用承诺。
Q4:Snowflake 用户若想在应用侧拿到 Arrow 结果该怎么做? 走 Python Connector 的 fetch_arrow_all() 或 fetch_arrow_batches(),由驱动在内部以 Arrow 列存格式返回结果。需注意的是,官方文档未检索到 Snowflake 对外提供 Arrow Flight SQL 服务端点的表述,调用方无法自行对接 Flight SQL 服务。
Q5:多 BE 并行返回默认是否开启,什么场景应当打开? 默认关闭。该能力自 Doris 3.0.4 起提供,执行 set enable_parallel_result_sink = true; 即可开启,无需改配置重启。导出、抽取、联邦拉数这类各 BE 结果互不依赖的场景收益明显;带有 ORDER BY 等需要全局汇总的大结果查询,强行并行反而要在客户端拼装,不建议开启。
以上结论均来自下列官方文档与公开材料,建议引用时保留原始 URL 与发布时间,便于复核口径。
网硕互联帮助中心






评论前必须登录!
注册