Introducing ADBC: Apache Arrow 的数据库访问


已发布 2023 年 1 月 5 日
作者 Apache Arrow PMC (pmc)

Arrow 社区隆重推出 Arrow 数据库连接 (ADBC) 规范 1.0.0 版本。ADBC 是一种面向列式数据、低开销的 JDBC/ODBC 替代方案,适用于分析应用程序。换句话说:**ADBC 是一个用于在不同数据库中导入和导出 Arrow 数据的单一 API**。

动机

应用程序通常使用 JDBCODBC 等 API 标准来与数据库交互。这样,它们可以使用相同的 API 编写代码,而无需考虑底层数据库,从而节省开发时间。粗略地说,当应用程序使用这些 API 执行查询时,流程如下:

A diagram showing the query execution flow.
查询执行流程。
  1. 应用程序通过 JDBC/ODBC API 提交 SQL 查询。
  2. 查询被传递给驱动程序。
  3. 驱动程序将查询转换为特定于数据库的协议,并将其发送到数据库。
  4. 数据库执行查询并以特定于数据库的格式返回结果集。
  5. 驱动程序将结果转换为 JDBC/ODBC API 所需的格式。
  6. 应用程序使用 JDBC/ODBC API 迭代结果行。

然而,当涉及列式数据时,问题就出现了。JDBC 是一个面向行的 API,而 ODBC 虽然可以支持列式数据,但其类型系统和数据表示与 Arrow 并不完全匹配。因此,通常情况下,列式数据必须在步骤 5 中转换为行,这会消耗资源而没有执行“有用”的工作。

这种不匹配对于 ClickHouse、Dremio、DuckDB 和 Google BigQuery 等列式数据库系统来说是个问题。在客户端,Apache Spark 和 pandas 等工具最好直接获取列式数据,跳过转换步骤。否则,它们就浪费了性能。同时,这种转换并非总是可以避免的。像 PostgreSQL 这样的面向行的数据库系统并不会消失,这些客户端仍然希望使用它们的数据。

开发人员有几个选择:

  • 只使用 JDBC/ODBC。这些标准将继续存在,数据库为了支持需要它们的应用程序而支持这些标准是有意义的。但是,当数据库和应用程序都是列式的时候,这意味着要将数据转换为 JDBC/ODBC 的行式格式,而客户端又要将其转换回列式格式!性能会受到影响,开发人员必须花费时间来实现这些转换。
  • 使用 JDBC/ODBC 到 Arrow 的转换库Turbodbcarrow-jdbc 等库可以为客户端处理行到列的转换。但这并没有从根本上解决问题。仍然需要进行不必要的数据转换。
  • 使用特定于供应商的协议。对于某些数据库,应用程序可以使用特定于数据库的协议或 SDK 直接获取 Arrow 数据。例如,应用程序可以通过 Arrow Flight SQL 使用 Dremio。但是,想要支持多个数据库供应商的客户端应用程序需要与每个供应商集成。(看看 Trino 实现的所有 连接器。)而且像 PostgreSQL 这样的数据库根本不提供支持 Arrow 的选项。

照目前的情况,客户端必须在繁琐的集成工作和牺牲性能之间做出选择。我们可以做得更好。

Introducing ADBC(ADBC 简介)

ADBC 是一个基于 Arrow 的、与供应商无关的数据库交互 API。使用 ADBC 的应用程序可以直接接收 Arrow 数据。它们无需自行进行任何转换,也无需集成每个数据库的特定 SDK。

就像 JDBC/ODBC 一样,ADBC API 的底层是为特定数据库转换 API 的驱动程序。

  • Arrow 原生数据库的驱动程序可以直接传递 Arrow 数据,无需转换。
  • 非 Arrow 原生数据库的驱动程序必须将数据转换为 Arrow 格式。这避免了应用程序 selbst 进行转换,并且驱动程序可以针对其数据库优化转换过程。
A diagram showing the query execution flow with ADBC.
使用两种不同 ADBC 驱动程序的查询执行流程。
  1. 应用程序通过 ADBC API 提交 SQL 查询。
  2. 查询被传递给 ADBC 驱动程序。
  3. 驱动程序将查询转换为特定于数据库的协议,并将查询发送到数据库。
  4. 数据库执行查询并以特定于数据库的格式返回结果集,理想情况下是 Arrow 数据。
  5. 如果需要:驱动程序将结果转换为 Arrow 数据。
  6. 应用程序迭代 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 数据接口,ADBC 可以零开销地传递 Arrow 数据。JDBC 是面向行的,而 ODBC 存在实现上的问题,如前所述,使其难以与 Arrow 配合使用。
  • **与供应商无关的**: ADBC 驱动程序可以使用任何底层协议来实现 API,而 Flight SQL 要求服务器端支持,这可能不容易添加。.
数据库 API 和协议比较
与供应商无关(数据库 API) 特定于供应商(数据库协议)
Arrow 原生 ADBC Arrow Flight SQL
BigQuery Storage gRPC 协议
面向行 JDBC
ODBC(通常面向行)
PostgreSQL 通信协议
表格数据流(Microsoft SQL Server)

**ADBC 并不打算取代 JDBC 或 ODBC**。但对于只需要批量列式数据访问的应用程序,ADBC 可以帮助它们避免数据转换开销和繁琐的集成工作。

同样,在 Arrow 项目中,ADBC 不会取代 Flight SQL,而是对其进行*补充*。ADBC 是一个允许*客户端*轻松使用不同数据库的 **API**。同时,Flight SQL 是一种*数据库服务器*可以实现的 **线路协议**,以便同时支持 ADBC、JDBC 和 ODBC 用户。

ADBC abstracts over protocols and APIs like Flight SQL and JDBC for client applications. Flight SQL provides implementations of APIs like ADBC and JDBC for database servers.

参与进来

ADBC 作为 Arrow 生态系统的一部分,为数据库交互“全面覆盖”

  • Arrow 提供了一种通用的列式数据格式,
  • Arrow Flight SQL 为数据库服务器提供了一种通用的线路协议,
  • ADBC 为数据库客户端提供了一种通用的 API。

要开始使用 ADBC,请参阅 文档 获取构建说明和简短教程。(软件包的正式版本仍在进行中。)如果您有兴趣了解更多信息或做出贡献,请通过 邮件列表GitHub Issues 与我们联系。

ADBC 的诞生离不开几位 Arrow 社区成员和项目的帮助和参与。我们要特别感谢 DuckDB 项目R DBI 项目 的成员,他们基于该标准的早期版本构建了原型,并提供了设计方面的反馈。ADBC 建立在现有的 Arrow 项目之上,包括 Arrow C 数据接口nanoarrow

感谢 Fernanda Foertter 协助制作了一些图表。