Arrow Flight SQL 最佳实践
Arrow Flight SQL 是从 StarRocks 中提取大型结果集的最快方式。在相同硬件和相同集群上,与 MySQL 协议相比,Arrow Flight 始终更快:**3×–9×原始协议获取速度快19×–97×**端到端到 pandas DataFrame 的速度更快。确切的倍数取决于行数、列结构以及所比较的 MySQL 客户端。但加速并非自动实现:客户端代码读取结果的方式对端到端时间有很大影响,一些简单的错误可能会抵消大部分性能提升。
本页展示了您可以预期的整体数据,总结了影响这些数据的各个方面,并结合代码变更和实测影响对每个方面进行了详细说明。
整体性能
以下进行两项比较。第一项仅衡量协议获取——字节到达并完成解析所需的时间,不涉及任何语言层面的对象转换。第二项衡量真实 Python 应用场景,其中数据被读入 pandas DataFrame。硬件信息请参见测试环境。
协议层获取(Arrow Flight ADBC 与 mysql --quick 对比)
fetch_arrow_table() 将网络数据直接写入 Arrow 缓冲区,无需将单元格转换为 Python 对象。mysql --quick 使用流式 C 客户端解析行,直接消费 MySQL 线协议。两者均为纯协议层操作——均不涉及语言原生对象的实例化开销 。
| 工作负载 | 行数 | MySQL 协议 ( mysql --quick) | Arrow Flight ( fetch_arrow_table) | 加速比 |
|---|---|---|---|---|
单数值列 (SELECT id) | 1 M | 831 ms | 215 ms | 3.9× |
单数值列 (SELECT id) | 5 M | 2,216 ms | 456 ms | 4.9× |
单数值列 (SELECT id) | 10 M | 4,166 ms | 1,163 ms | 3.6× |
单数值列 (SELECT id) | 100 M | 35,629 ms | 6,737 ms | 5.3× |
20 个数值列 (SELECT *) | 1 M | 1,994 ms | 370 ms | 5.4× |
20 个数值列 (SELECT *) | 5 M | 9,665 ms | 1,251 ms | 7.7× |
20 个数值列 (SELECT *) | 10 M | 18,461 ms | 2,577 ms | 7.2× |
20 个数值列 (SELECT *) | 100 M | 178,416 ms | 19,047 ms | 9.4× |
20 个 VARCHAR 列 (SELECT *) | 1 M | 4,549 ms | 1,294 ms | 3.5× |
20 个 VARCHAR 列 (SELECT *) | 5 M | 19,077 ms | 5,959 ms | 3.2× |
20 个 VARCHAR 列 (SELECT *) | 10 M | 36,079 ms | 11,499 ms | 3.1× |
20 个 VARCHAR 列 (SELECT *) | 100 M | 370,858 ms | 164,508 ms(分块) | 2.3× |
真实 Python 应用场景 — pd.read_sql 对比 ADBC 与 PyMySQL
Python 的标准管道是 pd.read_sql(sql, conn) → pandas.DataFrame。传入的连接对象决定了整个迁移方式:传入 PyMySQL 的 Connection,pandas 会调用 cursor.fetchall() + pd.DataFrame(rows),逐行遍历以构建 DataFrame。传入 ADBC Flight SQL 连接,pandas 则使用 ADBC 原生的 Arrow 获取方式,以及近零拷贝的 DataFrame 转换。
| 工作负载 | 行数 | pd.read_sql(sql,adbc_conn) | pd.read_sql(sql,pymysql_conn) | 加速比 |
|---|---|---|---|---|
单数值列(SELECT id) | 1 M | 320 ms | 6,185 ms | 19.3× |
单数值列(SELECT id) | 5 M | 421 ms | 30,751 ms | 73.0× |
单数值列(SELECT id) | 10 M | 970 ms | 61,524 ms | 63.4× |
单数值列(SELECT id) | 100 M | 6,024 ms | 585,556 ms | 97.2× |
20 个数值列(SELECT *) | 1 M | 522 ms | 27,521 ms | 52.7× |
20 个数值列(SELECT *) | 5 M | 1,530 ms | 141,500 ms | 92.5× |
20 个数值列(SELECT *) | 10 M | 2,689 ms | 255,408 ms | 95.0× |
20 个数值列(SELECT *) | 100 M | 24,568 ms | OOM | — |
20 个 VARCHAR 列(SELECT *) | 1 M | 1,560 ms | 31,407 ms | 20.1× |
20 个 VARCHAR 列(SELECT *) | 5 M | 6,937 ms | 154,560 ms | 22.3× |
20 个 VARCHAR 列(SELECT *) | 10 M | 13,260 ms | 304,647 ms | 23.0× |
每个单元格为获取 + 转换 = 总计;加速比为总时间之比。窄数值查询的加速比最大,原因在于 PyMySQL 在获取数据时会为每个单元格分配一个 Python int 对象,pandas 在转换时还需遍历元组列表——而 ADBC 两项开销均可跳过。Arrow 的列式内存格式双重获益:在获取阶段跳过了逐单元格的 Python 对象分配,并使后续的 DataFrame 转换几乎零开销。
如果您现有代码已使用 pd.read_sql,迁移只需一行:
import adbc_driver_manager
import adbc_driver_flightsql.dbapi as fl
import pandas as pd
with fl.connect(
uri="grpcs://host:443",
db_kwargs={
adbc_driver_manager.DatabaseOptions.USERNAME.value: "admin",
adbc_driver_manager.DatabaseOptions.PASSWORD.value: "...",
}) as conn:
df = pd.read_sql("SELECT * FROM my_table LIMIT 5000000", conn)
测试环境
| 组件 | 详情 |
|---|---|