使用 turbodbc 将关系型数据库连接到 Apache Arrow 世界
发布 2017 年 6 月 16 日
作者 Michael König (MathMagique)
Michael König 是 turbodbc 项目的首席开发人员
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 表并填充缓冲值。
- 重复前面的步骤,直到检索到整个结果集。
{:class="img-responsive" width="75%"}
在实践中,可以实现以下理想情况:一个 64 位整数列在列式数据库中存储为一个连续的内存块。一大块 64 位整数通过网络传输,ODBC 驱动程序直接将其写入 64 位整数的 turbodbc 缓冲区。Arrow 前端通过将整个 64 位缓冲区复制到 Arrow 表的 64 位整数列的空闲部分来累积这些值。
将数据从数据库移动到 Arrow 表,从而将其提供给 Python 用户,可以像复制内存块一样简单,一次传输数兆字节,相当于数十万行。没有序列化和转换逻辑使得该过程效率极高。
一旦数据存储在 Arrow 表中,Python 用户就可以继续进行实际工作。他们可以将其转换为 Pandas DataFrame 进行数据分析(使用快速的 table.to_pandas()),将其传递给其他数据处理系统,如 Apache Spark 或 Apache Impala (孵化中),或者以 Apache Parquet 文件格式存储。这样,非 Python 系统可以与关系型数据库高效连接。
未来,turbodbc 的 Arrow 支持将扩展以使用更复杂的功能,例如字典编码的字符串字段。我们还计划在可能的情况下选择小于 64 位的数据类型。最后但同样重要的是,Arrow 支持将扩展以涵盖数据流的逆向方向,以便 Python 用户可以快速将 Arrow 表插入关系型数据库。
如果您想了解更多关于 turbodbc 的信息,请查看 GitHub 项目和项目文档。如果您想了解 turbodbc 如何实现这些细节,请查看 Blue Yonder 的技术博客上 "Making of turbodbc" 系列的第一部分和第二部分。