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 的选项。

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

ADBC 简介

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

就像 JDBC/ODBC 一样,ADBC API 下方是用于特定数据库的驱动程序。

  • Arrow 原生数据库的驱动程序直接传递 Arrow 数据,无需转换。
  • 非 Arrow 原生数据库的驱动程序必须将数据转换为 Arrow。这使得应用程序无需执行此操作,并且驱动程序可以针对其数据库优化转换。
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://: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 原生:ADBC 可以通过 C 数据接口 无开销地传递 Arrow 数据。JDBC 是面向行的,而 ODBC 有如前所述的实现问题,这使得它难以与 Arrow 一起使用。
  • 与供应商无关:ADBC 驱动程序可以使用任何底层协议实现 API,而 Flight SQL 要求服务器端支持,这可能不容易添加。
比较数据库 API 和协议
与供应商无关(数据库 API) 与供应商相关(数据库协议)
Arrow 原生 ADBC Arrow Flight SQL
BigQuery 存储 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 协助绘制了一些图表。