增强 PostgreSQL GSoC2011 的 FDW 功能

来自 PostgreSQL wiki
跳转到导航跳转到搜索

想法

两个 FDW 允许用户访问

 1.CouchDB code: https://github.com/ZhengYang/couchdb_fdw
 2.ODBC enabled DBMS code: https://github.com/ZhengYang/odbc_fdw

详情

CouchDB FDW

一般来说,开发 FDW 的主要工作是实现 6 个回调函数

       * PlanForeignScan
       * ExplainForeignScan
       * BeginForeignScan
       * IterateForeignScan
       * ReScanForeignScan
       * EndForeignScan
CouchDB 外部服务器选项
  • address: CouchDB 服务器的地址或主机名。
    • 默认值:127.0.0.1
  • port: CouchDB 服务器监听的端口号。
    • 默认值:5984
CouchDB 外部表选项
  • database: 要查询的 CouchDB 数据库名称。
    • 默认值:test
  • <column name>: 与远程 JSON 属性的列映射。如果没有指定列映射,则默认值为原始列名。请注意,'_doc' 预留用于映射整个 JSON 文档。格式将是 <foreign table col_name> '<JSON attr name>'
CouchDB 用户映射选项
  • username: 用于向 CouchDB 服务器进行身份验证的用户名。
    • 默认值:<none>
  • password: 用于向 CouchDB 服务器进行身份验证的密码。
    • 默认值:<none>
功能细节
  1. 如果没有要下推的限定条件,我们会首先获取 '_id' 列表,然后在构建元组时获取仍然存在的记录。
  2. 我们只能将 '_id'(带有或不带有 '_rev')下推到 CouchDB,它必须使用 TEXTEQ 运算符。
  3. 文档的顶层属性可以映射到外部表中的列。
  4. 如果你想将一个列映射到整个 JOSN 文档,请在外部表选项中使用列名 '_doc'(这意味着你的远程 CouchDB 不应该有名为 '_doc' 的顶层属性,否则会导致冲突)。
实现细节

关于 CouchDB 的一些背景信息

  • 仅提供 RESTful HTTP API。这里有一些可用的第三方包装器:http://wiki.apache.org/couchdb/Basics。不幸的是,C 包装器已过时,不再维护。根据维基百科“这个已经过时了。不要看它。如果你需要一个 C API,你需要自己写一个”。所以必须使用 curl 和一个 JSON 包装器(我的选择是 YAJL)来进行所有 API 调用。
  • 由于 FDW 仅供读取,我们只需要调用 curl GET 请求。以下是一些关于如何构建 URL 以访问 CouchDB 服务器的典型示例:假设服务器位于
   http://127.0.0.1:5984

URL A. 访问数据库的元信息(用于 ExpainForeignScan 提供外部表信息 & PlanForeignScan 提供基于当前数据库中文档大小和数量的成本)

   http://127.0.0.1:5984/db_name/ 
   returns useful information like "doc_count":4, "disk_size":49241

URL B. 获取数据库中的所有 '_id'(当没有限定条件或限定条件不基于 '_id' 时使用,即需要完全表扫描)

   http://127.0.0.1:5984/db_name/_all_docs
   returns all _id in database named 'db_name'.
    
   http://127.0.0.1:5984/db_name/_all_docs?startkey="doc2"&limit=2  
   order, limit, startkey can be set to retrieve a range of _id's (This is useful especially when db size is too large, we can retrieve part by part to save memory)

URL C. 获取具有 '_id' 和 '_rev' 的文档

   http://127.0.0.1:5984/db_name/some_id?rev=some_rev
   if rev is absent, the latest rev will be returned.

总体策略是

  1. 如果要检索单个记录(条件包含 '_id'),我们会调用 URL C 来获取记录。它速度快且效率高,因为只进行一次 HTTP 调用
    • 例如:SELECT * FROM test where _id = 'QWERTTYYUUU';
  2. 如果要检索一系列记录(所有记录或指定了除 '_id' 之外的过滤条件)。我们会使用 URL B 加载一批记录,然后使用 URL C 一次访问它们。当前批次记录迭代完成后,加载一批新记录。重复此操作,直到访问完所有记录。
    • 例如:SELECT * FROM test where name = 'tom';(这意味着要检索所有具有顶层属性 'name' 且值等于 'tom' 的 JSON 文档)

ODBC FDW

使用 ODBC 驱动程序连接到外部数据库。为了连接外部数据库,可以设置以下选项(确保计算机上安装了 ODBC 驱动程序管理器和驱动程序)

ODBC 外部服务器选项
  • dsn: 要连接到的外部数据库系统的数据库源名称。
    • 默认值:<none>
ODBC 外部表选项
  • database: 要查询的数据库名称。
    • 默认值:<none>
  • schema: 要查询的数据库的模式。
    • 默认值:<none>
  • table: 要查询的表的名称。
    • 默认值:<none>
  • sql_query: 可选:用于查询外部表的用户定义 SQL 语句。
    • 默认值:<none>
  • sql_count: 可选:用于计算外部表中记录数的用户定义 SQL 语句。
    • 默认值:<none>
  • <column name>: 与远程表列的列映射。

如果没有指定列映射,则默认值为原始列名。

ODBC 用户映射选项
  • username: 用于向外部服务器进行身份验证的用户名。
    • 默认值:<none>
  • password: 用于向外部服务器进行身份验证的密码。
    • 默认值:<none>
实现细节说明
  1. 选项 'dsn' 应该指向包含连接信息的有效数据源名称。通常可以在驱动程序管理器的配置文件中找到 DNS,并设置 DBMS 特定的参数。
  2. 虽然这里指定的一些参数有时也可以在 DSN 中指定,但仍然需要在这里再次指定,因为某些驱动程序无法正确加载配置文件中的参数(例如,MySQL 连接器无法从配置文件加载 'database')。
  3. 名称限定符从 SQL_QUALIFIER_NAME_SEPARATOR 获取,对于大多数数据库来说是“点符号”。对于 mysql,要完全限定表名,我们使用 <db_name>.<table_name>(MySQL 使用 db_name 作为模式)。但是对于 postgresql,我们使用 <db_name>.<schema>.<table_name>。因此,我的实现是让用户提供 db_name、schema 和 table_name,我们使用 <schema>SQL_QUALIFIER_NAME_SEPARATOR<table_name> 作为完全限定表名的格式。对于 mysql 用户,他们需要将模式指定为与 db_name 相同,这似乎是 mysql 系统隐含的。引号字符可以通过 SQL_IDENTIFIER_QUOTE_CHAR 确定。例如,对于 mysql 是反引号(`),而对于 postgresql 是双引号(")。因此,构造的查询类似于:SELECT <mapped column names> FROM <schema>< SQL_QUALIFIER_NAME_SEPARATOR >(WHERE ... 如果限定条件可以下推)
  4. COUNT() 函数用于提供计划器和解释函数的信息。SELECT COUNT(*) FROM <schema>< SQL_QUALIFIER_NAME_SEPARATOR >
  5. 尽管做出了上述标准化工作,但仍然可能存在使用自定义 SQL 语法的例外情况。因此,为了提供最终的灵活性,还可以设置两个可选参数,让用户提供自定义 SQL 语句。
    1. sql_query: 用于获取结果的自定义查询。此查询应包括(不一定限于)FDW 中的所有列。
      • 例如:SELECT * FROM test.test;(星号始终是方便的方法)
      • 例如:SELECT a, b, c, FROM test.test;(确保设置 {a, b, c} 包含外部表中的所有列)
      • 例如:SELECT b, c, a FROM test.test;(列的顺序无关紧要,FDW 将处理它 :-)
    2. sql_count: 用于计算将返回的行数的自定义查询。该查询应返回一个单行,其中元组的第一个元素包含作为计数结果的数字。
      • 例如:SELECT COUNT(id) FROM test.test;(这比默认的 COUNT(*) 更有效,因为只计算一列。结果相同)
      • 例如:SELECT MY_COUNT(*) FROM test.test;(如果默认计数函数不是 COUNT(),此选项也有帮助)
      • 例如:SELECT 9999;(有时,计数函数可能很耗费资源,因为它通常需要完全表扫描,此示例演示了如何绕过此步骤)
  6. 时间安排

    1. 2011 年 4 月下旬(第 1 周):研究和阅读 mysql_fdw 和 redis_fdw

    2. 2011 年 5 月(第 2~5 周):热身并实现 CouchDB FDW。为 Linux 发行版之一的 iODBC 驱动程序实现 ODBC FDW。

    3. 2011 年 6 月(第 6~9 周):为 Windows 上的 Microsoft 驱动程序实现 ODBC FDW。为 ODBC FDW 实现复杂的限定条件下推。

    4. 2011 年 7 月(第 10~13 周):完成复杂限定条件下推功能。

    5. 2011 年 8 月(第 14~16 周):文档和测试。