跳到主要内容

外部数据

PostgreSQL 的外部数据包装器(Foreign Data Wrapper,FDW)让数据库通过类似本地表的 SQL 接口访问外部数据源。外部源可以是另一个 PostgreSQL 数据库,也可以是其他数据库、文件或服务,具体能力由扩展实现。

FDW 基于 SQL/MED 思想,核心对象包括:

  1. 外部数据包装器:提供连接某类数据源的实现;
  2. 外部服务器:描述一个具体远程端点;
  3. 用户映射:把本地角色映射到远程身份;
  4. 外部表:定义远程对象在本地看到的列结构。

本文使用 PostgreSQL 自带的 postgres_fdw 连接另一个 PostgreSQL 数据库。其他 FDW 的事务、下推和写入能力可能完全不同。

启用扩展​

CREATE EXTENSION postgres_fdw;

创建扩展通常需要较高权限。扩展代码运行在数据库服务端进程中,应只安装来源可信、版本兼容且经过运维审批的扩展。

创建外部服务器​

CREATE SERVER reporting_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (
host 'reporting-db.internal',
port '5432',
dbname 'reporting'
);

服务器对象保存连接端点配置,不应把普通用户密码直接写在这里。

可通过 ALTER SERVER 修改选项:

ALTER SERVER reporting_server
OPTIONS (SET host 'reporting-db-v2.internal');

网络 DNS、TLS、证书和防火墙仍需在数据库服务器所在环境正确配置。

创建用户映射​

CREATE USER MAPPING FOR app_runtime
SERVER reporting_server
OPTIONS (
user 'report_reader',
password 'managed-secret'
);

示例只展示语法。生产密码不应出现在版本库、聊天记录或可被普通用户读取的迁移日志中。根据环境选择密钥管理、服务文件、证书或目标 FDW 支持的认证方式。

也可以为 PUBLIC 创建映射,但这会扩大使用范围,通常应为明确角色分别配置。

创建外部表​

手工定义:

CREATE FOREIGN TABLE remote_orders (
order_id BIGINT NOT NULL,
customer_id BIGINT NOT NULL,
total_amount NUMERIC(12, 2) NOT NULL,
ordered_at TIMESTAMPTZ NOT NULL
)
SERVER reporting_server
OPTIONS (
schema_name 'sales',
table_name 'orders'
);

查询方式与本地表相似:

SELECT order_id, total_amount
FROM remote_orders
WHERE ordered_at >= CURRENT_DATE - INTERVAL '7 days';

外部表只保存本地元数据,不会自动复制远程数据。

导入远程模式​

postgres_fdw 可批量导入远程表定义:

CREATE SCHEMA remote_sales;

IMPORT FOREIGN SCHEMA sales
LIMIT TO (orders, order_items)
FROM SERVER reporting_server
INTO remote_sales;

还可以使用 EXCEPT 排除对象。导入只是创建当时的本地外部表定义;远程后来新增列、改类型或删除表时,本地定义不会自动同步。需要把远程结构变更纳入双方兼容和迁移流程。

查询下推​

FDW 可以把部分过滤、连接、聚合、排序等操作发送到远程执行,这称为下推(pushdown)。下推能减少网络传输,但是否发生取决于:

  • FDW 实现能力;
  • 本地与远程版本;
  • 数据类型、排序规则和函数语义;
  • 查询形状和成本估算;
  • 服务器及外部表选项。

使用 EXPLAIN VERBOSE 检查远程 SQL:

EXPLAIN (VERBOSE, COSTS OFF)
SELECT customer_id, sum(total_amount)
FROM remote_orders
WHERE ordered_at >= DATE '2026-09-01'
GROUP BY customer_id;

如果过滤没有下推,数据库可能先传输大量远程行再在本地处理。任何性能判断都应以实际计划、网络延迟和数据量为依据。

远程统计信息​

优化器需要估计远程表的行数和分布。可对外部表执行支持的分析:

ANALYZE remote_orders;

postgres_fdw 也提供影响远程估算方式的选项。获取更准确估算可能增加远程规划请求;使用本地统计则可能因数据变化而过期。应结合查询频率和远程数据变化选择。

写入外部表​

支持写入的 FDW 可以执行:

INSERT INTO remote_orders (...)
VALUES (...);

postgres_fdw 支持多种远程写入,但仍要注意:

  • 远程表约束与触发器在远端执行;
  • 本地外部表声明的约束通常是优化器所相信的元数据,不一定由本地强制检查;
  • 生成值和 RETURNING 支持取决于 FDW;
  • 网络中断会让错误恢复更复杂;
  • 批量逐行往返可能很慢。

不要把外部表上的本地 NOT NULL、CHECK 等声明误认为远程数据一定满足。只有在远端确实保证规则时,才能安全向本地优化器作出相应承诺。

事务语义​

访问远程数据时,本地事务与远程事务需要协调。postgres_fdw 会管理远程连接和事务,但跨多个外部服务器的原子提交、故障恢复和两阶段提交支持具有版本与配置限制。

不能简单假设:

本地表更新 + 多个远程数据库更新 = 任意故障下都原子提交

关键跨库写入应明确故障模型,并考虑:

  • 只读 FDW;
  • 单一写入权威;
  • 事件与补偿流程;
  • 幂等重试;
  • 数据对账;
  • 经验证的分布式事务能力。

长事务也可能在远端保留快照和锁,放大维护影响。

连接管理​

FDW 连接由 PostgreSQL 后端进程按需建立并复用。大量本地会话访问多个外部服务器时,远端连接数可能快速增长。

应监控:

  • 本地会话数与远程连接数;
  • 空闲连接复用和断开行为;
  • 查询超时、连接超时和 TCP 保活;
  • 远端连接池与最大连接限制;
  • 凭据轮换后的连接刷新。

不要把应用连接池只限制本地连接数,就认为远端一定不会耗尽连接。

权限​

使用外部服务器通常涉及多层权限:

  • 本地数据库中外部服务器的 USAGE;
  • 本地模式 USAGE;
  • 本地外部表的 SELECT / INSERT 等权限;
  • 用户映射的管理权限;
  • 远端映射角色对远程对象的权限。
GRANT USAGE ON FOREIGN SERVER reporting_server
TO app_runtime;

GRANT USAGE ON SCHEMA remote_sales TO app_runtime;
GRANT SELECT ON ALL TABLES IN SCHEMA remote_sales
TO app_runtime;

远端账户也应遵循最小权限。只读报表不应使用远端表所有者或超级用户凭据。

安全边界​

外部连接会把数据库服务器变成访问远程网络的客户端。应审查:

  • 远端主机是否可信且使用加密连接;
  • 证书是否正确验证;
  • 凭据存储与轮换;
  • 哪些本地角色可以创建或修改服务器和映射;
  • 查询参数、错误信息和日志是否泄露敏感数据;
  • FDW 扩展本身的供应链与更新机制。

即使本地 RLS 生效,也不能自动代表远端表采用同样策略。安全规则应在数据权威所在端强制执行。

外部表、复制与 ETL​

FDW 适合实时、按需访问,但不是所有集成任务的最佳选择:

方案更适合的场景
FDW中低延迟按需查询、数据量可控、可接受远程依赖
逻辑复制持续复制本地可查询副本、读多写少
ETL/ELT批量转换、历史仓库、复杂清洗
API需要业务授权和稳定服务契约

如果查询必须在远端故障时继续、需要大量重复扫描或复杂本地连接,复制到本地往往比每次跨网络读取更可靠。

常见误区​

外部表就是本地缓存​

不是。查询通常会访问远端,延迟和可用性受网络与远端影响。

本地约束会自动验证远端数据​

外部表约束可能只是优化器提示,具体强制能力取决于 FDW。权威约束应在远端建立。

所有条件都会下推​

函数、类型、排序规则和 FDW 能力都会限制下推。使用 EXPLAIN VERBOSE 验证。

一个本地事务天然保证跨库原子性​

跨服务器提交和故障恢复更复杂,必须按目标版本和 FDW 能力设计。

外部数据检查清单​

  1. 为什么选择实时外部访问,而不是复制、ETL 或 API;
  2. FDW 是否可信、受维护并兼容当前 PostgreSQL 版本;
  3. 远端结构变更如何同步到本地外部表定义;
  4. 关键过滤、连接和聚合是否实际下推;
  5. 远程统计与成本估算是否足够准确;
  6. 跨库写入的事务和故障恢复语义是否明确;
  7. 本地与远端角色是否都遵循最小权限;
  8. 凭据、TLS 和网络访问是否安全;
  9. 连接数、超时、远端故障和重试是否受控;
  10. 是否监控查询延迟、传输行数和远端负载。

FDW 的优势是让外部数据可以参与 SQL 查询,代价是把网络、远端权限、结构兼容和事务边界带进本地数据库。把它当作分布式系统接口,而不是一张“稍远的本地表”,设计会更可靠。