有这样的一个业务场景。有一个表对象在数据库 A 中,但是在同一个实例的数据库 B 中我想访问位于 A 库中的这个对象,那么有什么好的方法可以实现呢。
假设在数据库 cloud_test 中有如下的对象,现在想在数据库 cloud_health 中访问这个对象。
CREATE TABLE "public"."vaf1" (
"vaf01" int8 NOT NULL,
"vaf01a" int8,
"vaf01b" int8,
"vaf04" int2,
"vaa01" int8 NOT NULL,
"vaf06" int8,
"vaf07" int8,
"bck01a" int4,
"rownr" int4,
"bbx01" int4,
"vaf14" varchar(60),
"vaf15" varchar(30),
"bby01" int4,
"vaf36" timestamp(6),
PRIMARY KEY ("vaf01")
);
ALTER TABLE "public"."vaf1" OWNER TO "postgres";
CREATE INDEX "ix_vaf1_bbx01" ON "public"."vaf1" USING btree ("bbx01");
CREATE INDEX "ix_vaf1_vaf01a" ON "public"."vaf1" USING btree ("vaf01a");
CREATE INDEX "ix_vaf1_vaf36" ON "public"."vaf1" USING btree ("vaf36");
方案一:使用外部表实现
因为是 cloud_health 访问 cloud_test 数据库,所以需要在 cloud_health 数据库中安装外部插件。反之则在 cloud_test 中进行安装。
在 cloud_health 数据库中先看下外部表插件是否已经安装,如果没有则安装外部表插件。
SELECT * FROM pg_extension WHERE extname = 'postgres_fdw';
CREATE EXTENSION IF NOT EXISTS postgres_fdw;
建立一个外部服务,这个服务指向 cloud_test 数据库
CREATE SERVER IF NOT EXISTS server_remote_140 FOREIGN DATA WRAPPER postgres_fdw options(host '192.168.30.140',port '5432',dbname 'cloud_test');
说明:其中 server_remote_140 这个是外部服务器的名称,自己配置一个名称即可。()中的是数据库服务器的连接配置。
创建一个外部映射
create user mapping for postgres server server_remote_140 options(user 'postgres',password 'Centos@2024');
注意:这里的用户映射是需要存在的用户。SERVER 是前面创建的外部服务器的名称。
创建一个外部表
CREATE FOREIGN TABLE ft_vaf1(vaf01 int8 NOT NULL,vaf01a int8,vaf01b int8,vaf04 int2,vaa01 int8 NOT NULL,vaf06 int8,vaf07 int8,bck01a int4,rownr int4,bbx01 int4,vaf14 varchar(60),vaf15 varchar(30),bby01 int4,vaf36 timestamp(6)) server server_remote_140 options (schema_name 'public',table_name 'vaf1');
说明:ft_vaf1 是外部表的名称,这个表是在 cloud_health 数据库中的,这个表的字段需要跟 cloud_test 中的 vaf1 的字段相同。
备注:需要说明的是在外部表中是不支持键值的定义的。也就是说在外部表上不允许创建主键值。
在 cloud_health 数据库中直接访问 ft_vaf1 表,其内容与 cloud_test 中的 vaf1 表数据相同。
在 cloud_test 数据库的 vaf1 表中插入如下的数据。
INSERT INTO "public"."vaf1" ("vaf01", "vaf01a", "vaf01b", "vaf04", "vaa01", "vaf06", "vaf07", "bck01a", "rownr", "vaf14", "vaf15", "bby01", "vaf36") VALUES (934376602115133442, 934376602115133440, 0, 1, 511562834249924608, 934374864771502081, 0, 18, 2, NULL, '11633', 11956, '2024-01-23 09:18:54');
INSERT INTO "public"."vaf1" ("vaf01", "vaf01a", "vaf01b", "vaf04", "vaa01", "vaf06", "vaf07", "bck01a", "rownr", "vaf14", "vaf15", "bby01", "vaf36") VALUES (934376602115133441, 934376602115133440, 0, 1, 511562834249924608, 934374864771502081, 0, 18, 1, NULL, '11633', 1601584, '2024-01-23 09:18:54');
INSERT INTO "public"."vaf1" ("vaf01", "vaf01a", "vaf01b", "vaf04", "vaa01", "vaf06", "vaf07", "bck01a", "rownr", "vaf14", "vaf15", "bby01", "vaf36") VALUES (934376602115133440, 0, 0, 1, 511562834249924608, 934374864771502081, 0, 18, 0, NULL, NULL, 0, '2024-01-23 09:18:59');
INSERT INTO "public"."vaf1" ("vaf01", "vaf01a", "vaf01b", "vaf04", "vaa01", "vaf06", "vaf07", "bck01a", "rownr", "vaf14", "vaf15", "bby01", "vaf36") VALUES (932591980117118979, 932591980117118978, 0, 1, 932588467865677824, 932588468067004416, 0, 15, 1, NULL, '11633', 6494, '2024-01-18 11:06:57');
INSERT INTO "public"."vaf1" ("vaf01", "vaf01a", "vaf01b", "vaf04", "vaa01", "vaf06", "vaf07", "bck01a", "rownr", "vaf14", "vaf15", "bby01", "vaf36") VALUES (932591980117118978, 0, 0, 1, 932588467865677824, 932588468067004416, 0, 15, 0, NULL, NULL, 0, '2024-01-18 11:07:32');
INSERT INTO "public"."vaf1" ("vaf01", "vaf01a", "vaf01b", "vaf04", "vaa01", "vaf06", "vaf07", "bck01a", "rownr", "vaf14", "vaf15", "bby01", "vaf36") VALUES (932591980117118977, 932591980117118976, 0, 1, 932588467865677824, 932588468067004416, 0, 15, 1, NULL, '11574', 6341, '2024-01-18 11:06:57');
在 cloud_health 数据库的 ft_vaf1 表中查询数据。
SELECT * FROM ft_vaf1;
方案二:使用 DBLINK 实现
跟前面一样,我们需要在数据库 cloud_health 中安装 dblink 插件。
create extension if not exists dblink;
select * from dblink('host=192.168.30.140 port=5432 user=postgres dbname=cloud_test password=Centos@2024'::text,'select * from vaf1'::text)t (column_name type);
方案三:通过 PostgreSQL 的逻辑解析功能,发布订阅来实现。发布订阅的实现逻辑相对复杂一些,涉及好几个方面的知识和一些规则设置,我这里不详细讲解了,后面会配合 CDC 的那一篇详细讲一下。