【问题标题】:Possible to perform cross-database queries with PostgreSQL?可以使用 PostgreSQL 执行跨数据库查询吗?
【发布时间】:2010-09-07 23:04:20
【问题描述】:

根据下面的错误消息(和this Google result),我猜答案是“否”,但无论如何可以使用 PostgreSQL 执行跨数据库查询吗?

databaseA=# select * from databaseB.public.someTableName;
ERROR:  cross-database references are not implemented:
 "databaseB.public.someTableName"

我正在处理一些跨两个数据库分区的数据,尽管数据实际上在两个数据库之间共享(一个数据库中的用户 ID 列来自另一个数据库中的 users 表)。我不知道为什么这些是两个独立的数据库而不是模式,但是 c'est la vie...

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    注意:正如最初的提问者暗示的那样,如果您在同一台机器上设置两个数据库,您可能想要创建两个 schemas - 在这种情况下,您不需要任何特殊的东西来查询它们.

    postgres_fdw

    使用postgres_fdw(外部数据包装器)连接到任何 Postgres 数据库中的表 - 本地或远程。

    注意有foreign data wrappers for other popular data sources。目前,只有 postgres_fdwfile_fdw 是 Postgres 官方发行版的一部分。

    对于 9.3 之前的 Postgres 版本

    不再支持这个旧版本,但如果您需要在 2013 年之前的 Postgres 安装中执行此操作,则有一个名为 dblink 的函数。

    我从未使用过它,但它与 PostgreSQL 的其余部分一起维护和分发。如果您使用的是 Linux 发行版附带的 PostgreSQL 版本,您可能需要安装一个名为 postgresql-contrib 的软件包。

    【讨论】:

    • 需要在dblink之前安装postgresql-contrib?还是postgresql-contrib 包括dblink?然后 OP 的查询将起作用,还是您必须以不同的方式查询它?
    • 据我所知,dblink 无法处理您想要跨两个数据库的查询的情况。
    • 但是关于性能和简单性fdw表不是远程时,正如问题中所有跨数据库都是本地的并且在同一个集群中?所有documentation is about "remote database" (!) 和什么都不说关于“本地数据库”...当所有数据库都是本地数据库时会有一些简化和/或一些性能提升??跨度>
    【解决方案2】:

    dblink() -- 在远程数据库中执行查询

    dblink 执行一个查询(通常是一个 SELECT,但它可以是任何 SQL 返回行的语句)在远程数据库中。

    当给定两个文本参数时,首先查找第一个为 持久连接的名称;如果找到,则执行命令 那个连接。如果未找到,则将第一个参数视为 与 dblink_connect 相同的连接信息字符串,以及指示的 仅在此命令执行期间建立连接。

    一个很好的例子:

    SELECT * 
    FROM   table1 tb1 
    LEFT   JOIN (
       SELECT *
       FROM   dblink('dbname=db2','SELECT id, code FROM table2')
       AS     tb2(id int, code text);
    ) AS tb2 ON tb2.column = tb1.column;
    

    注意:我提供此信息以供将来参考。 Refrence

    【讨论】:

    • 别忘了创建扩展CREATE EXTENSION IF NOT EXISTS dblink;
    【解决方案3】:

    在得出与您一样的跨数据库查询结论之前,我已经遇到过这个问题。我最终做的是使用模式来划分表空间,这样我可以将表分组但仍然查询它们。

    【讨论】:

    • 如果您来自 MySQL 环境,那么 MySQL 所称的数据库实际上是模式(在 MySQL 中 CREATE SCHEMA == CREATE DATABASE),因此如果您使用多个数据库从 MySQL 移植某些内容,请使用模式
    【解决方案4】:

    只是补充一点信息。

    除了当前数据库之外,没有其他方法可以查询数据库。因为 PostgreSQL 加载特定于数据库的系统目录,所以甚至不确定跨数据库查询应该如何表现。

    contrib/dblink 允许使用函数调用进行跨数据库查询。当然,客户端也可以同时连接不同的数据库,并在客户端合并结果。

    PostgreSQL FAQ

    【讨论】:

    • 此附加信息可能具有误导性,可能会阻止用户使用上述解决方案。
    【解决方案5】:

    是的,您可以使用 DBlink(仅限 postgresql)和 DBI-Link(允许外部跨数据库查询器)和 TDS_LInk,它允许针对 MS SQL 服务器运行查询。

    我之前使用过 DB-Link 和 TDS-link,非常成功。

    【讨论】:

      【解决方案6】:

      如果性能很重要并且大多数查询都是只读的,我建议将数据复制到另一个数据库。虽然这似乎是不必要的数据重复,但如果需要索引,它可能会有所帮助。

      这可以通过简单的插入触发器来完成,该触发器又调用 dblink 来更新另一个副本。还有成熟的复制选项(如 Slony),但这是题外话。

      【讨论】:

        【解决方案7】:

        我已经检查并尝试使用 dblinkpostgres_fdw 在 2 个不同数据库中的 2 个表之间创建外键关系,但没有结果。

        阅读了其他人对此的反馈,例如 herehere 以及在其他一些来源中,目前似乎没有办法做到这一点:

        dblinkpostgres_fdw 确实可以连接和查询其他数据库中的表,这是标准 Postgres 无法做到的,但它们不允许建立不同数据库中表之间的外键关系。

        【讨论】:

          【解决方案8】:

          https://www.cybertec-postgresql.com/en/joining-data-from-multiple-postgres-databases/ [2017 年发布]

          现在你也可以选择使用https://prestodb.io/

          您可以在该 PrestoDB 节点上运行 SQL,它会根据需要分发 SQL 查询。它可以为不同的数据库连接到同一个节点两次,也可能连接到不同主机上的不同节点。

          不支持:

          DELETE
          ALTER TABLE
          CREATE TABLE (CREATE TABLE AS is supported)
          GRANT
          REVOKE
          SHOW GRANTS
          SHOW ROLES
          SHOW ROLE GRANTS
          

          所以您应该只将它用于 SELECT 和 JOIN 需求。直接连接到每个数据库以满足上述需求。 (看起来你也可以 INSERT 或 UPDATE 这很好)

          客户端应用程序主要使用 JDBC 连接到 PrestoDB,但也可以使用其他类型的连接,包括 Tableu compatible web API

          这是一个由 Linux 基金会和 Presto 基金会管理的开源工具。

          Presto 基金会的创始成员是:Facebook、Uber、 Twitter 和阿里巴巴。

          目前成员有:Facebook、Uber、Twitter、阿里巴巴、Alluxio、 Ahana、Upsolver 和英特尔。

          【讨论】:

          • 我应该使用 Presto 还是 Trino?
          【解决方案9】:

          如果有人需要更多有关如何进行跨数据库查询的示例,下面是一个清理每个数据库上的 databasechangeloglock 表的示例:

          CREATE EXTENSION IF NOT EXISTS dblink;
          
          DO 
          $$
          DECLARE database_name TEXT;
          DECLARE conn_template TEXT;
          DECLARE conn_string TEXT;
          DECLARE table_exists Boolean;
          BEGIN
              conn_template = 'user=myuser password=mypass dbname=';
          
              FOR database_name IN
                  SELECT datname FROM pg_database
                  WHERE datistemplate = false
              LOOP
                  conn_string = conn_template || database_name;
          
                  table_exists = (select table_exists_ from dblink(conn_string, '(select Count(*) > 0 from information_schema.tables where table_name = ''databasechangeloglock'')') as (table_exists_ Boolean));
                  IF table_exists THEN
                      perform dblink_exec(conn_string, 'delete from databasechangeloglock');
                  END IF;     
              END LOOP;
          
          END
          $$
          

          【讨论】:

            猜你喜欢
            • 2014-11-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-10-15
            相关资源
            最近更新 更多