使用 turbodbc 将关系型数据库连接到 Apache Arrow 世界


发布 2017 年 6 月 16 日
作者 Michael König (MathMagique)

Michael Königturbodbc 项目的首席开发人员

Apache Arrow 项目旨在成为面向列式数据处理系统的通用数据层,同时避免序列化开销,并在更通用的层面上不损害性能。尽管关系型数据库在 Apache Arrow 的采用方面仍然滞后,但 Python 数据库模块 turbodbc 通过使用一个更旧、更专业的数据交换层 ODBC,为这些数据库带来了 Apache Arrow 支持。

ODBC 是一种数据库接口,它为开发人员提供了以行式或列式方式传输数据的选项。以前的 Python ODBC 模块通常使用行式方法,并且经常以重复的数据库往返来换取简化的缓冲区处理。这使得它们不太适合数据密集型应用程序,尤其是在与现代列式分析数据库接口时。

相比之下,turbodbc 从一开始就被设计用于利用列式数据处理。当然,这意味着要使用 ODBC API 的列式部分。然而,同样重要的是要找到向 Python 用户提供列式数据的新方法,这些方法超越了 Python 的 PEP 249 所要求的行式 API 的功能。Turbodbc 已在最近发布的 2.0.0 版本中为此任务采用了 Apache Arrow。

>>> from turbodbc import connect
>>> connection = connect(dsn="My columnar database")
>>> cursor = connection.cursor()
>>> cursor.execute("SELECT some_integers, some_strings FROM my_table")
>>> cursor.fetchallarrow()
pyarrow.Table
some_integers: int64
some_strings: string

通过此新增功能,典型 SELECT 查询结果集的数据流如下所示:

  • 数据库准备结果集,并使用行式或列式存储将其暴露给 ODBC 驱动程序。
  • Turbodbc 让 ODBC 驱动程序将结果集的块写入列式缓冲区。
  • 这些缓冲区暴露给 turbodbc 的 Apache Arrow 前端。此前端将创建一个 Arrow 表并填充缓冲值。
  • 重复前面的步骤,直到检索到整个结果集。

使用 turbodbc 和 Apache Arrow 前端将数据从关系型数据库流式传输到 Python{:class="img-responsive" width="75%"}

在实践中,可以实现以下理想情况:一个 64 位整数列在列式数据库中存储为一个连续的内存块。一大块 64 位整数通过网络传输,ODBC 驱动程序直接将其写入 64 位整数的 turbodbc 缓冲区。Arrow 前端通过将整个 64 位缓冲区复制到 Arrow 表的 64 位整数列的空闲部分来累积这些值。

将数据从数据库移动到 Arrow 表,从而将其提供给 Python 用户,可以像复制内存块一样简单,一次传输数兆字节,相当于数十万行。没有序列化和转换逻辑使得该过程效率极高。

一旦数据存储在 Arrow 表中,Python 用户就可以继续进行实际工作。他们可以将其转换为 Pandas DataFrame 进行数据分析(使用快速的 table.to_pandas()),将其传递给其他数据处理系统,如 Apache SparkApache Impala (孵化中),或者以 Apache Parquet 文件格式存储。这样,非 Python 系统可以与关系型数据库高效连接。

未来,turbodbc 的 Arrow 支持将扩展以使用更复杂的功能,例如字典编码的字符串字段。我们还计划在可能的情况下选择小于 64 位的数据类型。最后但同样重要的是,Arrow 支持将扩展以涵盖数据流的逆向方向,以便 Python 用户可以快速将 Arrow 表插入关系型数据库。

如果您想了解更多关于 turbodbc 的信息,请查看 GitHub 项目项目文档。如果您想了解 turbodbc 如何实现这些细节,请查看 Blue Yonder 的技术博客"Making of turbodbc" 系列的第一部分第二部分