常见问题解答 (FAQ)

ADBC 到底是什么?

ADBC 是

  • 一组用不同语言(C/C++、Go 和 Java,以及更多正在开发中的语言)编写的抽象 API,用于处理数据库和 Arrow 数据。

    例如,ADBC 中查询的结果集都以 Arrow 数据流的形式返回,而不是逐行返回。

  • 一组用不同语言(C/C++、C#/.NET、Go、Java、Python 和 Ruby)实现的 API,它们针对不同的数据库(例如 PostgreSQL、SQLite、任何支持 Flight SQL 的数据库)。

为什么不直接使用 JDBC/ODBC?

JDBC 使用基于行的接口,例如 ResultSet。在处理列式数据(如 Arrow 数据)时,这意味着我们至少需要转换一次,甚至可能两次数据

  • 一次(可能)在驱动程序或数据库中,将列式数据转换为基于行的格式,以便可以通过 JDBC API 返回。

  • 一次(总是)当客户端应用程序从 JDBC API 中提取数据时,将行转换为列。

为了符合 Arrow 的“零拷贝”或“最小拷贝”理念,我们希望避免这些不必要的转换。

ODBC 处于类似的情况。尽管 ODBC 支持 “基于列的绑定”,但并非所有 ODBC 驱动程序都支持它,并且使用起来更加复杂。此外,ODBC 使用调用者分配的缓冲区(这通常意味着强制数据复制),并且 ODBC 指定的数据布局与 Arrow 不完全兼容(无论如何都需要数据转换)。

因此,我们认为仅仅扩展 ODBC 无法满足 ADBC 的目标。ODBC 对于更广泛的数据库支持始终具有价值,并且在 ODBC 之上提供基于 Arrow 的 API 非常有用。ADBC 将允许在一个通用库中实现/优化此转换,为使用者提供更简单的接口,并将提供一个 Arrow 本地或其他列式系统可以实现的 API,以绕过此包装器。

为什么 ODBC/Arrow 不太适合彼此

ODBC 通过 块游标 提供了对批量数据的支持,并且 Turbodbc 演示了可以在其之上构建高性能的基于 Arrow 的 API。但是,它仍然与 Arrow 不太匹配

  • 空值(“指示器”值) 表示为整数,需要转换。

  • 结果缓冲区由调用者分配。这可能会强制不必要地复制数据。ADBC 使用 C 数据接口,在可能的情况下消除复制(例如,如果驱动程序使用 Flight SQL)。

  • 某些数据类型表示不同,需要转换。 SQL_C_BINARY 可以为协作的驱动程序和应用程序规避此问题,但随后应用程序必须以不同的方式处理基于 Arrow 和非基于 Arrow 的数据源。

    • 字符串必须以 null 结尾,这将需要复制到 Arrow 数组中,或者要求应用程序处理数组中的 null 结尾字符串。

    • 字符串是否可以包含嵌入式空值是实现定义的,但 Arrow 指定了 UTF-8 字符串,其中 0x00 是一个有效字节。

    • 由于缓冲区由调用者分配,因此驱动程序和应用程序必须协作处理大型字符串; 驱动程序必须截断值,并且应用程序可以尝试再次获取该值。

    • ODBC 使用长度缓冲区而不是偏移量,需要另一个转换为/来自 Arrow 字符串数组的转换。

    • 时间间隔使用不同的表示形式.

ADBC 和 Arrow Flight SQL 有什么区别?

ADBC 是一个客户端 API 规范。它没有定义客户端和数据库之间发生的事情,只是定义了作为应用程序开发人员进行的 API 调用。在后台,驱动程序必须接收这些 API 调用并与实际的数据库进行通信。另一种观点是,ADBC 完全关注客户端,并且没有指定网络协议或服务器端实现。

Flight SQL 是一个线协议。它指定了发送到数据库以执行各种操作(如对数据库进行身份验证、创建预准备语句或执行查询)的确切命令。Flight SQL 指定了客户端和服务器必须实现的网络协议。

再换一种说法:可以为数据库编写一个纯粹作为客户端库的 ADBC 驱动程序。(例如,此存储库中的 PostgreSQL 驱动程序就是这样实现的——作为 libpq 的包装器。)但是,为数据库添加 Flight SQL 支持意味着要么修改数据库以运行 Flight SQL 服务,要么将数据库置于代理后面,该代理在 Flight SQL 和数据库之间进行转换。

为什么不直接使用 Arrow Flight SQL?

因为 ADBC 是客户端的,所以 ADBC 可以支持那些不支持返回 Arrow 数据或通过除 Flight SQL 之外的协议支持 Arrow 数据的数据库。

那么我们还需要 Arrow Flight SQL 吗?

Flight SQL 是一种具体的协议,数据库供应商可以实现它,而不是设计自己的协议。Flight SQL 还具有 JDBC 和 ODBC 驱动程序,以实现最大的兼容性。

打个比方:许多数据库实现了 PostgreSQL 线协议,以便它们可以访问所有 PostgreSQL 客户端,包括 JDBC 和 ODBC 驱动程序。(JDBC/ODBC 用户仍然可以使用其他驱动程序来处理其他数据库。)

对于 Arrow 生态系统,我们希望数据库将实现 Flight SQL 线协议,从而使它们能够访问所有 Flight SQL 客户端,包括 ADBC、JDBC 和 ODBC 驱动程序。(ADBC 用户仍然可以使用其他驱动程序来处理其他数据库。)

那么“ADBC Flight SQL 驱动程序”是什么呢?

ADBC Flight SQL 驱动程序使用 Flight SQL 线协议(数据库服务器公开)实现了 ADBC API 标准(应用程序与其交互)。因此,它是一个通用的驱动程序,只要这些数据库实现了 Flight SQL,它就可以与许多数据库通信。

这有点不寻常,因为您会发现大多数数据库驱动程序和数据库协议都是为特定数据库设计的。但是,Flight SQL 从一开始就被设计为与数据库无关,ADBC 也是如此。

听起来它们有重叠,但它们互为补充,因为它们在不同的抽象级别上运行。数据库开发人员只需提供 Flight SQL 服务,就可以免费获得 ADBC、JDBC 和 ODBC 驱动程序,而无需自行构建和维护这些驱动程序。数据库用户只需使用 ADBC 作为与 Arrow 本地和非 Arrow 本地数据库交互的唯一 Arrow 本地 API,无论这些数据库是否支持 Flight SQL、自定义 Arrow 本地协议或任何 Arrow 本地协议。

那么“ADBC JDBC 驱动程序”又是什么呢?

ADBC JDBC 驱动程序或假设的 ADBC ODBC 驱动程序将 JDBC API 适配到 ADBC API,以便 ADBC 用户可以与具有 JDBC API 可用的数据库进行交互。虽然这不会为您提供最佳性能(您需要为来回传输数据付费!),但它确实节省了您自己编写这些转换的麻烦。

类似的库已经存在;例如, Turbodbc 将任何 ODBC 驱动程序包装在 Python 的 DBAPI(PEP 249)中,并且 arrow-jdbc 将任何 JDBC 驱动程序包装在一个定制的基于 Arrow 的 API 中。

所有这些 API 如何协同工作?

_images/AdbcQuadrants.mmd.svg

我们可以根据两个轴将 API 分为两类:Arrow 本地与面向行,以及特定于数据库与与数据库无关。

与数据库无关的 API 与供应商无关,包括 ADBC、JDBC、ODBC,以及某种程度上 Flight SQL。(如上所述,Flight SQL 仍然需要特定的供应商支持;xDBCs 则不需要。)

特定于数据库的 API 由供应商为其系统创建,尽管其他系统最终可能会重新实现这些 API 以实现兼容性(就像通常对 PostgreSQL 线协议所做的那样)。

Arrow 本地 API(如 ADBC、Flight SQL 和 BigQuery 存储 API)本机返回 Arrow 数据,或者更一般地返回列式数据。这可以为处理大量数据的应用程序提供性能优势。

面向行的 API(如 JDBC、ODBC 和 PostgreSQL 线协议)一次处理一行数据。这对于某些类型的应用程序来说可能更方便

什么是 ADBC 驱动程序管理器?

驱动程序管理器(在 C/C++ 中)是一个实现驱动程序 API 但在后台动态加载和管理多个驱动程序的库。它允许应用程序链接到单个库,但同时使用多个驱动程序。这避免了多个驱动程序之间的符号冲突,否则所有这些驱动程序都将在相同名称下提供相同的 ADBC API。

有关深入了解,请参阅 驱动程序和驱动程序管理器如何协同工作

什么是 ADBC SQL 方言?

这是一个陷阱问题!ADBC 不是 SQL 方言。ADBC 驱动程序需要做的所有事情就是将您的查询字符串传递给数据库,并将结果集作为 Arrow 数据获取。在这方面,它类似于 JDBC。(ODBC 定义了它自己的“标准”SQL 方言;ADBC 没有这样做。)

对于一个尝试解决定义与供应商无关的查询语言问题的项目,请参阅 Substrait

下一个版本何时发布?

没有固定的发布节奏。我们目前的目标是每 6-8 周发布一次。

标记发布版本后,项目将至少提供 72 小时的时间供 Arrow PMC 对发布版本进行投票。投票结束后,软件包将上传到 PyPI、conda-forge 等位置。因此,即使在发布后,二进制软件包也可能需要一段时间才能可用。

1.0 何时/何地发布?这个项目准备好了吗?

项目的不同部分具有不同的版本号。我们认为某些实现(如 Go)已准备好“1.0”,而其他实现(如 Java)仍处于 1.0 之前的阶段。驱动程序实现状态 对各个驱动程序实现的状态进行了粗略概述。