乐于分享
好东西不私藏

一文搞懂 PostgreSQL:实例、模板与外部数据访问

一文搞懂 PostgreSQL:实例、模板与外部数据访问

管理数据库与数据库实例数据库(Database)数据库实例(Instance)管理数据库和模版数据库模版template0template1管理数据库实例:命令pg_ctl管理数据库的扩展访问外部的数据源file_fdw:访问外部的文件系统postgres_fdw:访问外部的文件系统oracle_fdw:访问外部的文件系统

管理数据库与数据库实例

数据库(Database)

它是数据的 “存储结构”,可以理解为 “装数据的容器”。

  • 逻辑存储结构:我们在 SQL 里直接打交道的对象,比如数据库集群、库、表空间、表、索引等,是 “用户视角” 的数据组织方式。

  • 物理存储结构:真正存在磁盘上的文件,比如数据文件、日志文件,是 “底层视角” 的实现方式。

  • 核心关系:数据库系统会通过逻辑结构,来管理和组织物理上的文件,让你不用直接操作磁盘。

数据库实例(Instance)

它是数据库运行时的 “进程 + 内存结构”,是让数据库能干活的 “引擎”。

  • 由内存(比如共享缓冲区、日志缓冲区)和后台进程组成。

  • 你平时启动 pg_ctl start,启动的就是这个实例;实例没起来,就算磁盘上有数据文件,也没法访问。

PostgreSQL 场景下的补充

在你用的 PostgreSQL 里,这两个概念非常好理解:

  • 你用 pg_ctl start 启动的,就是 PostgreSQL 实例(进程 + 内存)。

  • 你用 CREATE DATABASE scott; 创建的,就是 数据库对象,它最终会在数据目录下生成对应的物理文件。

PostgreSQL / MySQL:1 个实例,N 个数据库

  • 关系:1 个数据库实例(进程 + 内存),可以管理 N 个独立的数据库。

  • 理解:

    • 你启动一次 pg_ctl start 或 mysqld,就启动了一个实例。

    • 在这个实例里,你可以 CREATE DATABASE scott; 创建多个数据库,它们共享同一个实例的进程和内存。

Oracle(非 RAC):1 个实例,1 个数据库

  • 关系:1 个实例,对应 1 个数据库。

  • 理解:Oracle 的传统架构里,一个实例只能挂载一个数据库。要多库就得启动多个实例。

Oracle RAC:N 个实例,1 个数据库

  • 关系:多个实例(节点),同时挂载同一个数据库,实现高可用和负载均衡。

  • 理解:

    • 这是 Oracle 的集群架构,多个服务器上的实例,同时访问同一份数据文件。

    • 好处是一个节点挂了,其他节点还能继续提供服务。

管理数据库和模版

管理数据库和模版1、管理数据库    (1)创建数据库        create database mypgsql;        select datname from pg_database;    (2)修改数据库实例配置        (*)执行SQL命令 set        (*)配置文件:postgresql.conf        (*)执行shell命令    (3)删除数据库   drop database mypgsql;2、数据库模版:template0、template1
修改数据库实例配置        (*)执行SQL命令set(会话级修改)只对当前会话生效,断开连接后恢复默认。        示例:修改当前会话的工作内存postgres=# show work_mem ; work_mem ---------- 4MB(1 row)postgres=# set work_mem = '64MB';SETpostgres=# show work_mem ; work_mem ---------- 64MB(1 row) (*)配置文件:postgresql.conf(全局永久修改)修改配置文件后需要重启数据库服务才能生效。# 示例:修改最大连接数max_connections =200[postgres@pg15 ~]$ cd training/pgsql/data/[postgres@pg15 data]$ vim postgresql.conf找到max_connections =修改成200#重启数据库[postgres@pg15 pgsql]$ pg_ctl-D data -l logfile restartwaiting for server to shut down.... doneserver stoppedwaiting for server to start.... doneserver started[postgres@pg15 pgsql]$ pg_ctl-D data statuspg_ctl: server is running (PID: 90154)/home/postgres/training/pgsql/bin/postgres "-D""data"[postgres@pg15 pgsql](*)执行shell命令[postgres@pg15 pgsql]$ bin/pg_ctl -D data/ -l logfile stopwaiting for server to shut down.... doneserver stopped[postgres@pg15 pgsql]$ bin/postgres -cwork_mem='8MB'2026-05-1716:40:12.518 CST [112438] LOG:  starting PostgreSQL 15.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit2026-05-1716:40:12.520 CST [112438] LOG:  listening on IPv6 address "::1", port 54322026-05-1716:40:12.520 CST [112438] LOG:  listening on IPv4 address "127.0.0.1", port 54322026-05-1716:40:12.522 CST [112438] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"2026-05-1716:40:12.524 CST [112446] LOG:  database system was shut down at 2026-05-1716:39:07 CST2026-05-1716:40:12.525 CST [112438] LOG:  database system is ready to accept connections#因为你这里按Ctrl+c数据库会直接不启动所以重新开个链接查看[root@pg15 ~]# su - postgres 上一次登录:日 5月 1710:12:15 CST 2026pts/0 上[postgres@pg15 ~]$ cd training/pgsql/[postgres@pg15 pgsql]$ cd bin/[postgres@pg15 bin]$ psqlpsql (15.3)Type "help"for help.postgres=# show work_mem; work_mem ---------- 8MB(1 row)postgres=修改成功

数据库模版

当我们创建启动一个数据库集群系统默认会有两个数据库模版 template0、template1这是标准的数据库对象

[postgres@pg15 pgsql]$ bin/pg_ctl -D data/ -l logfile startpg_ctl: another server might be running; trying to start server anywaywaiting for server to start.... doneserver started[postgres@pg15 pgsql]$ bin/pg_ctl -D data/ -l logfile statuspg_ctl: server is running (PID: 3637)/home/postgres/training/pgsql/bin/postgres "-D""data"[postgres@pg15 pgsql]$ bin/psql psql (15.3)Type "help"for help.postgres=# select datname from pg_database;  datname  ----------- postgres scott template1 template0(4 rows)

template0

template0:当数据库集群被初始化成功后,不应该修改它保存的是pg数据库预定义的数据库对象

template1

template1: 跟template0保存的对象是一样的,当创建一个自定义数据库的时候实际上它是复制一个template1的模版。

select datname,datistemplate,datallowconn from pg_database;
  • datname:数据库名称

  • datistemplate:是否为模板库(t= 是,f= 否)

  • datallowconn:是否允许连接(t= 是,f= 否)

执行结果里:

  • template1datistemplate = tdatallowconn = t → 可修改、可连接、默认模板

  • template0datistemplate = tdatallowconn = f → 纯净模板、不可连接

#datistemplate表示是不是一个数据库模版,datallowconn表示是否允许建立连接postgres=# select datname,datistemplate,datallowconn from pg_database;  datname  | datistemplate | datallowconn -----------+---------------+-------------- postgres  | f             | t scott     | f             | t  template1 | t是模版数据库   | t template0 | t是模版数据库   | f   不允许建立连接 (4 rows)
特性template1template0
是否可修改✅ 可修改❌ 不可修改(初始化后不应改动)
创建新库时默认模板✅ 是(CREATE DATABASE 默认复制它)❌ 不是,需手动指定
是否允许连接✅ 允许(datallowconn = t❌ 不允许(datallowconn = f
用途作为默认模板,可自定义公共对象纯净备份模板,恢复 / 创建干净库时用

一句话总结

  • template1 是可定制的默认模板,改它 = 给所有新库加 “公共配置”。

  • template0 是只读的纯净备份,用来救急和创建干净库。

管理数据库实例:命令pg_ctl

[postgres@pg15 pgsql]$ bin/pg_ctl --helppg_ctl is a utility to initialize, startstop, or control a PostgreSQL server.Usage:  pg_ctl init[db]   [-D DATADIR] [-s] [-o OPTIONS]  pg_ctl start      [-D DATADIR] [-l FILENAME] [-W] [-t SECS] [-s]                    [-o OPTIONS] [-p PATH] [-c]  pg_ctl stop       [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]  pg_ctl restart    [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]                    [-o OPTIONS] [-c]  pg_ctl reload     [-D DATADIR] [-s]  pg_ctl status     [-D DATADIR]  pg_ctl promote    [-D DATADIR] [-W] [-t SECS] [-s]  pg_ctl logrotate  [-D DATADIR] [-s]  pg_ctl kill       SIGNALNAME PIDCommon options:-D--pgdata=DATADIR   location of the database storage area-s--silent           only print errors, no informational messages-t--timeout=SECS     seconds to wait when using -w option-V--version          output version information, thenexit-w--wait             wait until operation completes (default)-W--no-waitdo not wait until operation completes-?, --help             show this help, thenexitIf the -D option is omitted, the environment variable PGDATA is used.Options forstart or restart:-c--core-files       allow postgres to produce core files-l--log=FILENAME     write (or append) server log to FILENAME-o--options=OPTIONS  command line options to pass to postgres                         (PostgreSQL server executable) or initdb-p PATH-TO-POSTGRES    normally not necessaryOptions forstop or restart:-m--mode=MODE        MODE can be "smart""fast", or "immediate"Shutdown modes are:  smart       quit after all clients have disconnected  fast        quit directly, with proper shutdown (default)  immediate   quit without complete shutdown; will lead to recovery on restartAllowed signal names forkill:  ABRT HUP INT KILL QUIT TERM USR1 USR2Report bugs to <pgsql-bugs@lists.postgresql.org>.PostgreSQL home page: <https://www.postgresql.org/>
Usage:  pg_ctl init[db]   [-D DATADIR] [-s] [-o OPTIONS]  pg_ctl start      [-D DATADIR] [-l FILENAME] [-W] [-t SECS] [-s]                    [-o OPTIONS] [-p PATH] [-c]  pg_ctl stop       [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]  pg_ctl restart    [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]                    [-o OPTIONS] [-c]  pg_ctl reload     [-D DATADIR] [-s]  pg_ctl status     [-D DATADIR]  pg_ctl promote    [-D DATADIR] [-W] [-t SECS] [-s]  pg_ctl logrotate  [-D DATADIR] [-s]  pg_ctl kill       SIGNALNAME PID

初始化数据库(第一次用才执行)

pg_ctl initdb -D data

= 建一个空的数据库环境(删数据、重装时用)


1. pg_ctl start

作用:启动数据库

pg_ctl start -D data -l logfile

2. pg_ctl stop

作用:停止数据库

pg_ctl stop -D data

3. pg_ctl restart

作用:重启数据库(先停再起)

pg_ctl restart -D data

4. pg_ctl reload

作用:重新加载配置文件(不重启)


5. pg_ctl status

作用:看数据库有没有运行

pg_ctl status -D data

6. 其他(你暂时不用记)

  • promote:主从切换用

  • logrotate:日志切割

  • kill:强制杀进程


最重要的 2 个参数(必须懂)

-D DATADIR

数据目录在哪里

你永远写:

-D data

-l FILENAME

日志写在哪里

你永远写:

-l logfile

4 条常用命令

pg_ctl initdb -D data       # 初始化(删数据才用)pg_ctl start -D data -l logfile  # 启动pg_ctl stop -D data         # 停止pg_ctl status -D data       # 看状态

一句话终极总结

pg_ctl = PG 开关命令 -D 表示数据目录 start 启动 stop 停止 status 看状态

管理数据库的扩展

访问外部的数据源

file_fdw:访问外部的文件系统

编译和安装file_fdw

[postgres@pg15 ~]$ cd tools/postgresql-15.3/contrib/file_fdw/[postgres@pg15 file_fdw]$ make``````[postgres@pg15 file_fdw]$ make install``````

修改配置文件

[postgres@pg15 ~]$ cd training/pgsql/data/[postgres@pg15 data]$ vim postgresql.conf 用下面命令在vim找到这个参数/shared_preload    添加以下内容shared_preload_libraries ='file_fdw'保存退出

启动数据库实例

[postgres@pg15 data]$ cd ..[postgres@pg15 pgsql]$ bin/pg_ctl -D data/ -l logfile startwaiting for server to start.... doneserver started[postgres@pg15 pgsql]$ bin/pg_ctl -D data/ -l logfile statuspg_ctl: server is running (PID: 123146)/home/postgres/training/pgsql/bin/postgres "-D""data"

创建扩展插件

[postgres@pg15 pgsql]  bin/psql psql (15.3)Type "help"for help.postgres=# create extension file_fdw;CREATE EXTENSIONpostgres=#  select * from pg_extension;  oid  | extname  | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition -------+----------+----------+--------------+----------------+------------+-----------+--------------13673 | plpgsql  |       10 |           11 | f              | 1.0        |           | 16399 | file_fdw |       10 |         2200 | t              | 1.0        |           | (2 rows)postgres=# \x         #输入一次 \x → 开启(竖着展示,一行一个字段)Expanded display is on.postgres=# \x        #再输入一次 \x → 关闭(横着展示,表格形式)        Expanded display is off.postgres=# \xExpanded display is on.postgres=#  select * from pg_extension;    #查看数据库安装了哪些扩展插件-[ RECORD 1 ]--+---------oid            | 13673extname        | plpgsql        #系统自带的函数语言(必须有,删不掉)extowner       | 10extnamespace   | 11extrelocatable | fextversion     | 1.0extconfig      | extcondition   | -[ RECORD 2 ]--+---------oid            | 16399extname        | file_fdw     #用来读取外部文件的插件extowner       | 10extnamespace   | 2200extrelocatable | textversion     | 1.0extconfig      | extcondition   | 

做完以上内容就是安装成功了file_fdw

file_fdw:访问外部的文件系统

postgres=# create server service_file foreign data wrapper file_fdw;CREATE SERVERpostgres=# create foreign table ft_emppostgres-# (empno int,postgres(# ename varchar(10),postgres(# job varchar(10),postgres(# mgr int,postgres(# hiredate varchar(100),postgres(# sal int,postgres(# comn int,postgres(# deptno int)postgres-# server service_file optionspostgres-# (filename '/home/postgres/training/pgsql/emp.csv',format 'csv');CREATE FOREIGN TABLEpostgres=# select * from ft_emp;ERROR:  invalid input syntax for type integer: "empno"CONTEXT:  COPY ft_emp, line 1, column empno: "empno"#发现报错现在的外部表没告诉 PostgreSQL:CSV 第一行是表头,不是数据!#所以它把 empno 这个文字当成数字往里插,直接报错#排错先删掉旧的外部表postgres=# drop foreign table ft_emp;DROP FOREIGN TABLE#重新创建带header正确版本postgres=# create foreign table ft_emppostgres-# (empno int,postgres(# ename varchar(10),postgres(# job varchar(10),postgres(# mgr int,postgres(# hiredate varchar(100),postgres(# sal int,postgres(# comm int,postgres(# deptno int)postgres-# server service_file optionspostgres-# (postgres(# filename '/home/postgres/training/pgsql/emp.csv',postgres(# format 'csv',postgres(# header 'true'  #添加这一行,header 'true'= 跳过 CSV 第一行的表头postgres(# );postgres-# \xExpanded display is off.ostgres=# select * from ft_emp; empno | ename  |    job    | mgr  |  hiredate  | sal  | comm | deptno -------+--------+-----------+------+------------+------+------+--------7369 | SMITH  | CLERK     | 7902 | 1980/12/17 |  800 |      |     207499 | ALLEN  | SALESMAN  | 7698 | 1981/2/20  | 1600 |  300 |     307521 | WARD   | SALESMAN  | 7698 | 1981/2/22  | 1250 |  500 |     307566 | JONES  | MANAGER   | 7839 | 1981/4/2   | 2975 |      |     207654 | MARTIN | SALESMAN  | 7698 | 1981/9/28  | 1250 | 1400 |     307698 | BLAKE  | MANAGER   | 7839 | 1981/5/1   | 2850 |      |     307782 | CLARK  | MANAGER   | 7839 | 1981/6/9   | 2450 |      |     107788 | SCOTT  | ANALYST   | 7566 | 1987/4/19  | 3000 |      |     207839 | KING   | PRESIDENT |      | 1981/11/17 | 5000 |      |     107844 | TURNER | SALESMAN  | 7698 | 1981/9/8   | 1500 |    0 |     307876 | ADAMS  | CLERK     | 7788 | 1987/5/23  | 1100 |      |     207900 | JAMES  | CLERK     | 7698 | 1981/12/3  |  950 |      |     307902 | FORD   | ANALYST   | 7566 | 1981/12/3  | 3000 |      |     207934 | MILLER | CLERK     | 7782 | 1982/1/23  | 1300 |      |     10(14 rows)postgres=#

postgres_fdw:访问外部的文件系统

通过使用 file_fdw 扩展使得 PostgreSQL 能够访问外部文件系统中的数据文件,同样通过使用 postgres_fdw 扩展可以使得 PostgreSQL 能够访问外部远端的 PostgreSQL 数据库中的数据。下面通过具体的步骤操作来演示如何使用 postgres_fdw 扩展。

编译和安装postgres_fdw修改配置文件和上面file_fdw一致请参考上面这部分

#只是在修改配置文件的时候在后面添加插件名字用,隔开shared_preload_libraries ='file_fdw,postgres_fdw'

重启数据库实例

[postgres@pg15 pgsql]$ bin/pg_ctl -D data/ -l logfile restartwaiting for server to shut down.... doneserver stoppedwaiting for server to start.... doneserver started[postgres@pg15 pgsql]$ bin/pg_ctl -D data/ -l logfile statuspg_ctl: server is running (PID: 115560)/home/postgres/training/pgsql/bin/postgres "-D""data"

到这里postgres_fdw这个扩展插件就编译安装好了

postgres_fdw:访问外部的文件系统

#创建 postgres_fdw 扩展postgres=# create extension postgres_fdw;CREATE EXTENSIONpostgres=# \xExpanded display is on.postgres=# select * from pg_extension;-[ RECORD 1 ]--+-------------oid            | 13673extname        | plpgsqlextowner       | 10extnamespace   | 11extrelocatable | fextversion     | 1.0extconfig      | extcondition   | -[ RECORD 2 ]--+-------------oid            | 16399extname        | file_fdwextowner       | 10extnamespace   | 2200extrelocatable | textversion     | 1.0extconfig      | extcondition   | -[ RECORD 3 ]--+-------------oid            | 16410extname        | postgres_fdwextowner       | 10extnamespace   | 2200extrelocatable | textversion     | 1.1extconfig      | extcondition   |#创建远程服务器postgres=#   create server foreign_server foreign data wrapper postgres_fdwpostgres-# options (host 'localhost',port '5432',dbname 'scott');CREATE SERVER#创建用户映射create user mapping for postgresserver foreign_serveroptions (user 'postgres', password '你的postgres密码');postgres=# create user mapping for postgrespostgres-# server foreign_serverpostgres-# options (user 'postgres', password '你的postgres密码');CREATE USER MAPPING#创建远程外部表postgres=# create foreign table ft_dept (postgres(#     deptno int,postgres(#     dname varchar(14),postgres(#     loc varchar(13)postgres(# )postgres-# server foreign_serverpostgres-# options (schema_name 'public', table_name 'dept');CREATE FOREIGN TABLEpostgres=# \xExpanded display is off.#然后查询postgres=# select * from ft_dept; deptno |   dname    |   loc    --------+------------+----------10 | ACCOUNTING | NEW YORK20 | RESEARCH   | DALLAS30 | SALES      | CHICAGO40 | OPERATIONS | BOSTON(4 rows)#远程的外部表内容有更新也会同步到外部表里面[postgres@pg15 pgsql]$ bin/psql psql (15.3)Type "help"for help.postgres=# \c scott You are now connected to database "scott" as user "postgres".scott=# insert into dept values(50,'HR','WuHan');INSERT 01scott=# select * from dept; deptno |   dname    |   loc    --------+------------+----------10 | ACCOUNTING | NEW YORK20 | RESEARCH   | DALLAS30 | SALES      | CHICAGO40 | OPERATIONS | BOSTON50 | HR         | WuHan(5 rows)#去查询外部表postgres-# server foreign_serverpostgres-# options (schema_name 'public', table_name 'dept');CREATE FOREIGN TABLEpostgres=# \xExpanded display is off.postgres=# select * from ft_dept; deptno |   dname    |   loc    --------+------------+----------10 | ACCOUNTING | NEW YORK20 | RESEARCH   | DALLAS30 | SALES      | CHICAGO40 | OPERATIONS | BOSTON(4 rows)postgres=# select * from ft_dept; deptno |   dname    |   loc    --------+------------+----------10 | ACCOUNTING | NEW YORK20 | RESEARCH   | DALLAS30 | SALES      | CHICAGO40 | OPERATIONS | BOSTON50 | HR         | WuHan(5 rows)postgres=#

oracle_fdw:访问外部的文件系统

使用 Oracle 数据库扩展 oracle_fdw

使用oracle_fdw:访问外部的文件系统需要有orcal环境我会发orcal安装教程具体安装看后面更新的文章

与 file_fdw 和 postgres_fdw 扩展类似,oracle_fdw 也是 PostgreSQL 数据库支持的外部扩展。通过使用 oracle_fdw 扩展可以读取到 Oracle 数据库中的数据。它是一种非常方便且常见的 PostgreSQL 与 Oracle 的同步数据的方法。

oracle_fdw 扩展需要依赖 Oracle 的 Instance Client 环境。

Oracle Instant Client 的组件包下载地址:https://www.oracle.com/cn/database/technologies/instant-client/linux-x86-64-downloads.html

文件名作用必须下载吗?
instantclient-basic-linuxx64.zip基础运行库,oracle_fdw 必须依赖✅ 必须
instantclient-sqlplus-linuxx64.zip提供 sqlplus 命令行工具,方便你直接连 Oracle⭕ 推荐
instantclient-sdk-linuxx64.zip开发头文件,oracle_fdw 编译必须依赖✅ 必须
[postgres@pg15 ~]$ cd tools/instantclient/[postgres@pg15 instantclient]$ lsinstantclient-basic-linux.x64-19.31.0.0.0dbru.zip  instantclient-sdk-linux.x64-19.31.0.0.0dbru.zip  instantclient-sqlplus-linux.x64-19.31.0.0.0dbru.zip-- 分别解压三个安装包unzip instantclient-basic-linux.x64-19.31.0.0.0dbru.zip unzip instantclient-basic-linux.x64-19.31.0.0.0dbru.zip unzip instantclient-sqlplus-linux.x64-19.31.0.0.0dbru.zip -- 改个文件名方便辨认[postgres@pg15 instantclient]$ lsinstantclient_19_31  instantclient-basic-linux.x64-19.31.0.0.0dbru.zip  instantclient-sdk-linux.x64-19.31.0.0.0dbru.zip  instantclient-sqlplus-linux.x64-19.31.0.0.0dbru.zip  META-INF[postgres@pg15 instantclient]$ mv instantclient_19_31 instantclient[postgres@pg15 instantclient]$ lsinstantclient  instantclient-basic-linux.x64-19.31.0.0.0dbru.zip  instantclient-sdk-linux.x64-19.31.0.0.0dbru.zip  instantclient-sqlplus-linux.x64-19.31.0.0.0dbru.zip  META-INF-- 设置orcal环境变量[postgres@pg15 instantclient]$ vi ~/.bash_profile #添加以下内容exportORACLE_HOME=/home/postgres/tools/instantclient/instantclientexportOCI_LIB_DIR=$ORACLE_HOMEexportOCI_INC_DIR=$ORACLE_HOME/sdk/includeexportLD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH[postgres@pg15 instantclient]$ source ~/.bash_profile [postgres@pg15 instantclient]$ echo$ORACLE_HOME/home/postgres/tools/instantclient/instantclient-- 下载 oracle_fdw 源码[postgres@pg15 instantclient]$ cd ..wget https://github.com/laurenz/oracle_fdw/archive/refs/tags/ORACLE_FDW_2_6_0.tar.gz[postgres@pg15 tools]$ lsinstantclient  ORACLE_FDW_2_6_0.tar.gz  postgresql-15.3  postgresql-15.3.tar.gz-- 解压设置pg_config的环境变量并编译安装[postgres@pg15 tools]$ tar-zxvf ORACLE_FDW_2_6_0.tar.gz [postgres@pg15 oracle_fdw-ORACLE_FDW_2_6_0]$ exportPATH=/home/postgres/training/pgsql/bin:$PATH[postgres@pg15 oracle_fdw-ORACLE_FDW_2_6_0]$ which pg_config ~/training/pgsql/bin/pg_config--能输出 /home/postgres/training/pgsql/bin/pg_config,就说明环境已经完全配置好了,直接 make 即可[postgres@pg15 oracle_fdw-ORACLE_FDW_2_6_0]$ make[postgres@pg15 oracle_fdw-ORACLE_FDW_2_6_0]$ make install

使用root用户添加oracle依赖的库信息,添加完成后切换回postgres用户

为什么要做这一步?

oracle_fdw 运行时需要依赖 Oracle 客户端的 .so 库文件,通过 ldconfig 可以让系统全局识别这些库,避免在 PostgreSQL 运行时出现 error while loading shared libraries 这类错误。

[postgres@pg15 oracle_fdw-ORACLE_FDW_2_6_0]$ su- root[root@pg15 ~]# echo "/home/postgres/tools/instantclient/instantclient" > /etc/ld.so.conf.d/oracle.conf[root@pg15 ~]# ldconfig[root@pg15 ~]# su - postgres Last login: Thu May 2112:57:45 CST 2026 on pts/0[postgres@pg15 ~]

启动数据库创建扩展

[postgres@pg15 ~]$ cd training/pgsql/[postgres@pg15 pgsql]$ bin/pg_ctl -D data/ -l logfile startwaiting for server to start.... doneserver started-- 创建扩展[postgres@pg15 pgsql]$ bin/psql psql (15.3)Type "help"for help.postgres=# create extension oracle_fdw;CREATE EXTENSIONpostgres=#  \dx                               List of installed extensions     Name     | Version |   Schema   |                    Description                     --------------+---------+------------+---------------------------------------------------- file_fdw     | 1.0     | public     | foreign-data wrapper for flat file access oracle_fdw   | 1.2     | public     | foreign data wrapper for Oracle access plpgsql      | 1.0     | pg_catalog | PL/pgSQL procedural language postgres_fdw | 1.1     | public     | foreign-data wrapper for remote PostgreSQL servers(4 rows)

创建基于 oracle_fdw的外部数据库服务

-- 切换orcal账户看一下1521端口是不是正常监听和启动[root@pg15 ~]# su - oracle 上一次登录:四 5月 2113:37:30 CST 2026pts/4 上[oracle@pg15 ~]$ lsnrctl status如果看到 The listener supports no services 或者命令报错,说明监听没起来-- 就用下面命令启动监听[oracle@pg15 ~]$ lsnrctlstart-- 检查端口[oracle@pg15 ~]$ netstat-tlnp | grep1521(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)tcp6       00 :::1521                 :::*                    LISTEN      96638/tnslsnr-- 切换postgres账户创建基于 oracle_fdw的外部数据库服务su- postgres[postgres@pg15 ~]$ cd training/pgsql/[postgres@pg15 pgsql]$ bin/psql psql (15.3)Type "help"for help.postgres=# create server oracle_serverpostgres-# foreign data wrapper oracle_fdwpostgres-# options (dbserver '//192.168.10.139:1521/orcl');CREATE SERVERpostgres=# \xExpanded display is on.postgres=# \des+List of foreign servers-[ RECORD 1 ]--------+------------------------------------------------Name                 | foreign_serverOwner                | postgresForeign-data wrapper | postgres_fdwAccess privileges    | Type                 | Version              | FDW options          | (host 'localhost', port '5432', dbname 'scott')Description          | -[ RECORD 2 ]--------+------------------------------------------------Name                 | oracle_serverOwner                | postgresForeign-data wrapper | oracle_fdwAccess privileges    | Type                 | Version              | FDW options          | (dbserver '//192.168.10.139:1521/orcl')Description          | -[ RECORD 3 ]--------+------------------------------------------------Name                 | service_fileOwner                | postgresForeign-data wrapper | file_fdwAccess privileges    | Type                 | Version              | FDW options          | Description          | postgres=

创建postgreSQL与Oracle之间的用户映射

postgres=#  create user mapping for postgrespostgres-# server oracle_serverpostgres-# options (user 'scott', password 'tiger');CREATE USER MAPPING

在pgsql数据库中创建外部表访问orcal中的数据

postgres=# create foreign table oracle_emp(postgres(#   empno numeric(4,0) options (key 'true') not null,postgres(#   ename varchar(10),postgres(#   job varchar(9),postgres(#   mgr numeric(4,0),postgres(#   hiredate timestamp,postgres(#   sal numeric(7,2),postgres(#   comm numeric(7,2),postgres(#   deptno numeric(2,0)postgres(# ) server oracle_serverpostgres-# options (schema 'SCOTT', table 'EMP');CREATE FOREIGN TABLE-- 需要注意这里SCOTT和EMP需要大写-- 然后我们发现可以直接通过外部表访问oracle数据postgres=# select * from oracle_emp;-[ RECORD 1 ]-----------------empno    | 7369ename    | SMITHjob      | CLERKmgr      | 7902hiredate | 1980-12-1700:00:00sal      | 800.00comm     | deptno   | 20-[ RECORD 2 ]-----------------empno    | 7499ename    | ALLENjob      | SALESMANmgr      | 7698hiredate | 1981-02-2000:00:00sal      | 1600.00comm     | 300.00deptno   | 30-[ RECORD 3 ]-----------------empno    | 7521ename    | WARDjob      | SALESMANmgr      | 7698hiredate | 1981-02-2200:00:00sal      | 1250.00comm     | 500.00deptno   | 30postgres=-- 下面为orcal用户查看oracle表发现和数据和上面外部访问一样[oracle@pg15 ~]$ sqlplus / as sysdbaSQL*Plus: Release 19.0.0.0.0 - Production on Thu May 2115:46:20 2026Version 19.3.0.0.0Copyright (c) 19822019, Oracle.  All rights reserved.Connected to:Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - ProductionVersion 19.3.0.0.0SQL> conn scott/tigerConnected.SQL> select * from emp;     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM--------------------------------------------------------------------    DEPTNO----------7369 SMITH      CLERK           790217-DEC-80800207499 ALLEN      SALESMAN        769820-FEB-811600300307521 WARD       SALESMAN        769822-FEB-81125050030SQL> 

还有一种自导导入也可以通过在pgsql数据库访问orcal中的数据

特性自动导入 IMPORT FOREIGN SCHEMA手动创建 CREATE FOREIGN TABLE
创建方式一条命令自动生成逐张表、逐列手动定义
Schema / 表名完全继承 Oracle 的 schema 和表名可以自定义 PG 里的表名(比如 oracle_emp
字段定义自动按 Oracle 字段类型映射必须手动写清每一列的 PG 数据类型
主键 / 索引自动识别 Oracle 主键需手动通过 options (key 'true') 指定主键
适用场景快速迁移、一次性导入整个 schema只需要访问少数几张表,或需要自定义表结构
优缺点快、省事,但灵活性低灵活可控,但写起来麻烦,容易写错字段类型

自动把 Oracle 里的 把 Oracle scott 用户下的所有表全部导入 PG

import foreign schema scott from server oracle_server into public;--- 执行完,直接查select * from emp;

我这里就不演示了因为我pgsql里面有emp这个表自动导入命令它会试图在 PG 里再创建一张叫 empdept 的外部表表名重复 → 直接报错,创建失败!

总结

无论哪种方式,数据都不存在 PostgreSQL 里,外部表只是一个「代理」,查询时 PG 会把请求转发给 Oracle,再把结果返回给你。所以 Oracle 里的数据变了,PG 里查出来的结果也会跟着变