ADBC 简介:用于 Apache Arrow 的数据库访问
已发布 2023 年 1 月 5 日
作者 Apache Arrow PMC (pmc)
Arrow 社区很高兴推出 Arrow 数据库连接 (ADBC) 规范的 1.0.0 版本。 ADBC 是一种列式、低开销的 JDBC/ODBC 替代方案,适用于分析应用程序。 或者换句话说:ADBC 是一个用于在不同数据库中获取 Arrow 数据的单一 API。
动机
应用程序通常使用诸如 JDBC 和 ODBC 之类的 API 标准来与数据库交互。 这样,无论底层数据库如何,他们都可以使用相同的 API 进行编码,从而节省开发时间。 粗略地说,当应用程序使用这些 API 执行查询时
- 应用程序通过 JDBC/ODBC API 提交 SQL 查询。
- 查询传递给驱动程序。
- 驱动程序将查询转换为特定于数据库的协议,并将其发送到数据库。
- 数据库执行查询并以特定于数据库的格式返回结果集。
- 驱动程序将结果转换为 JDBC/ODBC API 要求的格式。
- 应用程序使用 JDBC/ODBC API 迭代结果行。
但是,当涉及到列式数据时,会出现问题。 JDBC 是一个面向行的 API,虽然 ODBC 可以支持列式数据,但类型系统和数据表示与 Arrow 并不完全匹配。 因此,通常,列式数据必须在第 5 步转换为行,从而在不执行“有用”工作的情况下花费资源。
这种不匹配对于 ClickHouse、Dremio、DuckDB 和 Google BigQuery 等列式数据库系统来说是有问题的。 在客户端,Apache Spark 和 pandas 等工具最好直接获取列式数据,跳过该转换。 否则,他们会浪费性能。 同时,这种转换并非总是可以避免的。 像 PostgreSQL 这样的面向行的数据库系统不会消失,这些客户端仍然希望使用它们的数据。
开发人员有几个选择
- 只需使用 JDBC/ODBC。 这些标准将长期存在,数据库支持它们以满足应用程序的需求是有意义的。 但是,当数据库和应用程序都是列式的时,这意味着将数据转换为 JDBC/ODBC 的行,而客户端又将其转换回列! 性能受到影响,开发人员必须花费时间来实现转换。
- 使用 JDBC/ODBC 到 Arrow 的转换库。 诸如 Turbodbc 和 arrow-jdbc 之类的库处理客户端的行到列的转换。 但这并没有从根本上解决问题。 仍然需要不必要的数据转换。
- 使用特定于供应商的协议。 对于某些数据库,应用程序可以使用特定于数据库的协议或 SDK 直接获取 Arrow 数据。 例如,应用程序可以通过 Arrow Flight SQL 使用 Dremio。 但是,想要支持多个数据库供应商的客户端应用程序需要与每个供应商集成。(看看 Trino 实现的所有连接器。)并且像 PostgreSQL 这样的数据库根本不提供支持 Arrow 的选项。
目前,客户端必须在繁琐的集成工作或浪费性能之间做出选择。 我们可以做得更好。
ADBC 简介
ADBC 是一个基于 Arrow、供应商中立的 API,用于与数据库交互。 使用 ADBC 的应用程序只需接收 Arrow 数据。 他们不必自己进行任何转换,也不必集成每个数据库的特定 SDK。
就像 JDBC/ODBC 一样,在 ADBC API 下面是为特定数据库转换 API 的驱动程序。
- 用于 Arrow 原生数据库的驱动程序只需直接传递 Arrow 数据,无需转换。
- 非 Arrow 原生数据库的驱动程序必须将数据转换为 Arrow。 这可以避免应用程序这样做,并且驱动程序可以针对其数据库优化转换。
- 应用程序通过 ADBC API 提交 SQL 查询。
- 查询传递给 ADBC 驱动程序。
- 驱动程序将查询转换为特定于数据库的协议,并将查询发送到数据库。
- 数据库执行查询并以特定于数据库的格式返回结果集,理想情况下是 Arrow 数据。
- 如果需要:驱动程序将结果转换为 Arrow 数据。
- 应用程序迭代批量的 Arrow 数据。
应用程序仅处理一个 API,并且仅使用 Arrow 数据。
ADBC API 和驱动程序实现正在开发中。 例如,在 Python 中,ADBC 包提供了一个熟悉的 DBAPI 2.0 (PEP 249) 风格的接口,并带有获取 Arrow 数据的扩展。 我们可以轻松地从 PostgreSQL 中获取 Arrow 数据
import adbc_driver_postgresql.dbapi
uri = "postgresql://localhost:5432/postgres?user=postgres&password=password"
with adbc_driver_postgresql.dbapi.connect(uri) as conn:
with conn.cursor() as cur:
cur.execute("SELECT * FROM customer")
table = cur.fetch_arrow_table()
# Process the results
或者 SQLite
import adbc_driver_sqlite.dbapi
uri = "file:mydb.sqlite"
with adbc_driver_sqlite.dbapi.connect(uri) as conn:
with conn.cursor() as cur:
cur.execute("SELECT * FROM customer")
table = cur.fetch_arrow_table()
# Process the results
注意:实现仍在开发中。 有关最新示例,请参阅文档。
关于 {Flight SQL, JDBC, ODBC, …} 呢?
ADBC 填补了相关项目未解决的特定领域。 它既是
- Arrow 原生:由于 C Data Interface,ADBC 可以零开销地传递 Arrow 数据。 如前所述,JDBC 是面向行的,ODBC 具有实现警告,使其难以与 Arrow 一起使用。
- 供应商无关:ADBC 驱动程序可以使用任何底层协议实现 API,而 Flight SQL 需要服务器端支持,这可能不容易添加。
供应商中立(数据库 API) | 特定于供应商(数据库协议) | |
---|---|---|
Arrow 原生 | ADBC | Arrow Flight SQL BigQuery Storage gRPC 协议 |
面向行 | JDBC ODBC(通常面向行) |
PostgreSQL wire 协议 Tabular Data Stream (Microsoft SQL Server) |
ADBC 并非旨在完全取代 JDBC 或 ODBC。 但是,对于只想进行批量列式数据访问的应用程序,ADBC 可以使它们避免数据转换开销和繁琐的集成工作。
类似地,在 Arrow 项目中,ADBC 不会取代 Flight SQL,而是补充它。 ADBC 是一个 API,可让客户端轻松地与不同的数据库交互。 同时,Flight SQL 是一种 wire 协议,数据库服务器可以实现该协议,以同时支持 ADBC、JDBC 和 ODBC 用户。
参与其中
ADBC 作为 Arrow 生态系统的一部分工作,以“覆盖”数据库交互的基础
- Arrow 提供通用的列式数据格式,
- Arrow Flight SQL 提供数据库服务器的通用 wire 协议,
- ADBC 为数据库客户端提供通用的 API。
要开始使用 ADBC,请参阅 文档 以获取构建说明和简短教程。(软件包的正式发布仍在进行中。)如果您有兴趣了解更多信息或做出贡献,请通过邮件列表或 GitHub Issues 与我们联系。
ADBC 的实现离不开多个 Arrow 社区成员和项目的帮助和参与。 特别是,我们要感谢 DuckDB 项目和 R DBI 项目的成员,他们基于该标准的早期版本构建了原型,并提供了有关设计的反馈。 并且 ADBC 构建在现有的 Arrow 项目之上,包括 Arrow C Data Interface 和 nanoarrow。
感谢 Fernanda Foertter 在一些图表方面的帮助。