可以使用PostgreSQL执行跨数据库查询吗?

Possible to perform cross-database queries with PostgreSQL?

提问人:matt b 提问时间:9/6/2008 最后编辑:Kenny Linskymatt b 更新时间:5/21/2023 访问量:338279

问:

根据下面的错误消息(以及这个 Google 结果),我猜测答案是“否”,但是有没有使用 PostgreSQL 执行跨数据库查询?

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

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

SQL PostgreSQL

评论


答:

25赞 stimms 9/6/2008 #1

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

评论

20赞 MkV 5/7/2010
如果你来自MySQL环境,MySQL所说的数据库实际上是模式(在MySQL中是CREATE SCHEMA == CREATE DATABASE),所以如果你使用多个数据库从MySQL移植一些东西,请使用模式
0赞 Shayne 6/28/2022
是的,Postgres的“数据库”本质上是完整的租户。他们存在于自己的宇宙中。(我已经看到MySQL将模式视为数据库而导致的可怕的安全漏洞。在一个托管站点上,我们的安全人员设法以某种方式获得了对大约 400 个其他数据库的完全访问权限。下一个版本修补了,但这绝对是一个混乱的问题)
158赞 Neall 9/6/2008 #2

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

postgres_fdw

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

请注意,其他常用数据源也有外部数据包装器。目前,只有 和 是官方 Postgres 发行版的一部分。postgres_fdwfile_fdw

对于 9.3 之前的 Postgres 版本

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

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

评论

1赞 mpen 6/20/2011
需要安装前吗?或包括 ?然后 OP 的查询将起作用,还是您必须以不同的方式查询它?postgresql-contribdblinkpostgresql-contribdblink
3赞 Paul Tomblin 3/27/2012
据我所知,dblink 无法处理您想要跨越两个数据库的查询的情况。
1赞 Peter Krauss 12/6/2021
但是,当 fdw 表不是远程时,关于性能和简单性,如问题中所示,所有跨数据库都是本地的并且在同一集群中?所有文档都是关于“远程数据库”(!)的,而没有提到“本地数据库”......当所有数据库都是本地数据库时,是否有一些简化和/或一些性能提升?
1赞 Peter Krauss 6/26/2022
如果您在同一个 pg 服务器中使用 FDW...外籍家政工人的表现很丑!我正在使用它,看起来很慢......所以我比较了相同的查询,它显示 FDW 查询慢了 ~450 倍!是的,在同一个数据库中使用 all 按 SQL 模式拆分内容。EXPLAIN ANALYZE
3赞 dpavlin 9/12/2008 #3

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

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

6赞 snorkel 9/22/2008 #4

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

我以前使用过 DB-Link 和 TDS-link,并取得了巨大的成功。

11赞 Esteban Küber 5/7/2010 #5

只是为了添加更多信息。

无法查询当前数据库以外的数据库。由于 PostgreSQL 加载特定于数据库的系统目录,因此不确定跨数据库查询的行为方式。

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

PostgreSQL 常见问题

评论

6赞 johan855 1/12/2017
此附加信息可能具有误导性,并可能阻止用户使用上述解决方案。
2赞 Shayne 6/28/2022
它不仅没有误导性,而且是正确的答案。其他解决方案不适用于许多用例。
66赞 4 revs, 3 users 64%Manwal #6

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;

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

评论

6赞 Igor Manoel 5/28/2021
不要忘记创建扩展CREATE EXTENSION IF NOT EXISTS dblink;
1赞 Rakesh Soni 5/1/2022
注意:我们可以在 dblink() 函数的第一个参数中传递 dbname、port、host、user、password 属性。示例 : dblink('dbname=testrds port=5432 host=testrds.rds.amazonaws.com user=testuser password=passwd', 'SELECT id, code FROM table2') AS tb2(id int, code text);
0赞 Adrian Moisa 4/28/2023
从设计微服务的角度来看,我认为这是不行的,因为数据库应该能够在两个不同的微服务之间独立迁移。使用此解决方案将在属于不同微服务的数据库之间创建紧密耦合。
1赞 Haroldo_OK 4/12/2019 #7

如果有人需要有关如何执行跨数据库查询的更复杂的示例,下面是一个示例,用于清理每个具有它的数据库上的表: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
$$
4赞 Rocckk 7/12/2019 #8

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

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

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

2赞 Kind Contributor 2/6/2021 #9

请参阅 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,但也可以进行其他类型的连接,包括与 Tableau 兼容的 Web API

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

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

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

评论

0赞 Kevin 7/8/2021
我应该使用 Presto 还是 Trino?
0赞 Oscar Bonilla 5/21/2023 #10

在 Sybase/MSSQLServer 中,逻辑组织是db.user.table

在 Oracle 中,逻辑组织是schema.table

我知道在PostgreSQL中是,但不能共享db.schema.tabledb

秘诀是在 Sybase 或 Oracle 中仅使用 2 级。db.<defaultuser.>tableschema.table

然后在 PostgreSQL 中,如果需要在级别之间共享表,请仅使用一个 db(不要创建多个数据库,仅使用 postgres),并使用多个模式,例如 Oracle:postgres.schemaX.table