操作指导
前置操作
- 连接GaussDB数据库时,需要在远程数据库节点机器上设置允许DATABASE LINK进行访问,并配置远程连接。
- DATABASE LINK连接Oracle数据库前,需要安装配置OCI(Oracle Call Interface)库。OCI配置步骤如下:
以下以Version 19.24.0.0.0 (Requires glibc 2.14) 版本为例。
下载 instantclient-basic-linux.x64-19.24.0.0.0dbru.zip文件。
- 访问Oracle数据库官网,选择对应的版本进行下载OCI库,具体通过官网下载链接进行下载。
- 解压下载的OCI库。
unzip instantclient-basic-linux.x64-19.24.0.0.0dbru.zip
- 设置环境变量参数,指定OCI库文件所在路径。
export ORACLE_HOME=/xxx/oracle_client_dir/instantclient_19_24 export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME:$LD_LIBRARY_PATH
- 若使用基于SSL的DATABASE LINK连接Oracle数据库时,需要额外配置wallet路径和TNS等信息,具体配置信息请参见《参考》中“SQL参考 > SQL语法 > C > CREATE DATABASE LINK”章节。
- 使用基于SSL的DATABASE LINK首次连接Oracle数据库时,需保证tnsnames.ora文件存在。若tnsnames.ora文件不存在则需要正确配置并重启GaussDB数据库后才可正常使用DATABASE LINK连接。
语法格式
- 创建DATABASE LINK。
- 创建DATABASE LINK对象,具体语法请参见《参考》中“SQL参考 > SQL语法 > C > CREATE DATABASE LINK”章节。
- 创建DATABASE LINK时可指定PUBLIC或PRIVATE,PRIVATE DATABASE LINK仅能被创建者进行访问,PUBLIC DATABASE LINK可被所有用户进行访问。所有已创建的DATABASE LINK信息都存放在本地数据库的系统视图GS_DB_LINKS中。
- 修改DATABASE LINK信息。
修改指定DATABASE LINK对象信息,具体语法请参见《参考》中“SQL参考 > SQL语法 > A > ALTER DATABASE LINK”章节。
- 删除DATABASE LINK。
删除指定DATABASE LINK对象,具体语法请参见《参考》中“SQL参考 > SQL语法 > D > DROP DATABASE LINK”章节。
- 使用DATABASE LINK操作远程对象。
- 通过DATABASE LINK进行SELECT操作。
[ WITH [ RECURSIVE ] with_query [, ...] ] SELECT [/*+ plan_hint */] [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] { * | {expression [ [ AS ] output_name ]} [, ...] } [ FROM from_item [, ...] ] [ WHERE condition ] [ [ START WITH condition ] CONNECT BY [NOCYCLE] condition [ ORDER SIBLINGS BY expression ] ] [ GROUP BY grouping_element [, ...] ] [ HAVING condition [, ...] ] [ { UNION | INTERSECT | EXCEPT | MINUS } [ ALL | DISTINCT ] select ] [ ORDER BY {expression [ [ ASC | DESC | USING operator ] | nlssort_expression_clause ] [ NULLS { FIRST | LAST } ]} [, ...] ] [ LIMIT { [offset,] count | ALL } ] [ OFFSET start [ ROW | ROWS ] ] [ {FOR { UPDATE | SHARE} [ OF table_name [, ...] ] } [...] ]; {[ ONLY ] table_name [ * ] [ partition_clause ] @ dblink [ [ AS ] alias [ ( column_alias [, ...] ) ] ] |( select ) [ AS ] alias [ ( column_alias [, ...] ) ] |with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ] |[function_name] ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ] |[function_name] ( [ argument [, ...] ] ) AS ( column_definition [, ...] ) |from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]}; - 通过DATABASE LINK进行INSERT操作。
[ WITH [ RECURSIVE ] with_query [, ...] ] INSERT [/*+ plan_hint */] INTO table_name [ partition_clause ] @ dblink [ ( column_name [, ...] ) ] { DEFAULT VALUES | VALUES {( { expression | DEFAULT } [, ...] ) }[, ...] | query } [ RETURNING { {output_expression [ [ AS ] output_name ] }[, ...]} ]; - 通过DATABASE LINK进行UPDATE操作。
UPDATE [/*+ plan_hint */] [ ONLY ] table_name [ partition_clause ] @ dblink [ [ AS ] alias ] SET {column_name = { expression | DEFAULT } |( column_name [, ...] ) = {( { expression | DEFAULT } [, ...] ) |sub_query }}[, ...] [ FROM from_list ] [ WHERE condition ] [ ORDER BY {expression [ [ ASC | DESC | USING operator ] | nlssort_expression_clause ] [ NULLS { FIRST | LAST } ]} [, ...] ] [ LIMIT { [offset,] count | ALL } ] [ RETURNING { {output_expression [ [ AS ] output_name ]} [, ...] }]; where sub_query can be: SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] { * | {expression [ [ AS ] output_name ]} [, ...] } [ FROM from_item [, ...] ] [ WHERE condition ] [ GROUP BY grouping_element [, ...] ] [ HAVING condition [, ...] ]; - 通过DATABASE LINK进行DELETE操作。
[ WITH [ RECURSIVE ] with_query [, ...] ] DELETE [/*+ plan_hint */] FROM [ ONLY ] table_name [ partition_clause ] @ dblink [ [ AS ] alias ] [ USING using_list ] [ WHERE condition] [ ORDER BY {expression [ [ ASC | DESC | USING operator ] | nlssort_expression_clause ] [ NULLS { FIRST | LAST } ]} [, ...] ] [ LIMIT { [offset,] count | ALL } ] [ RETURNING { * | { output_expr [ [ AS ] output_name ] } [, ...] } ]; - 通过DATABASE LINK进行LOCK TABLE操作。
LOCK [ TABLE ] {[ ONLY ] name @ dblink [, ...]} [ IN {ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE} MODE ] [ NOWAIT ]; - 调用远程数据库的存储过程或函数。
1CALL | SELECT [ schema. ] { func_name@dblink | procedure_name@dblink } ( param_expr );
- 通过DATABASE LINK进行SELECT操作。
规格约束
- 兼容性约束
- DATABASE LINK特性只在A兼容模式数据库下可以使用。
- DATABASE LINK特性支持连接GaussDB和Oracle数据库。
- 当通过DATABASE LINK连接GaussDB时,用户需要保证本地和远程数据库的兼容性参数DBCOMPATIBILITY和GUC参数behavior_compat_options、a_format_dev_version、a_format_version取值一致。
- 连接GaussDB时,DATABASE LINK开启远程连接事务前,会自动设置如下GUC参数:
SET search_path=pg_catalog, '$user', 'public'; SET explain_perf_mode='normal'; SET session_timeout=0; SET datestyle=ISO; SET intervalstyle=postgres; SET extra_float_digits=3;
其余参数为远程数据库设置的参数,远程参数与本地参数不同时,可能会出现数据显示格式不一致等情况,使用时应尽量保证远程与本地参数相同。
- 连接GaussDB时,远程数据库与本地数据库需要保证相同的datea类型,GUC参数mapping_date_to_datea才能正常使用。
- 字符集约束
- 当连接GaussDB时,如果本地数据库与远程数据库字符集不同,可能会出现无法转换,并返回远程的报错信息的情况。当本地数据库字符编码为GB18030_2022时,发送到远程的请求字符集编码被转换为GB18030。因此,若本地数据库的字符集为GB18030_2022时,远程数据库字符集只能是GB18030或GB18030_2022。
- 当连接Oracle数据库时,DATABASE LINK每次建立连接时会通过当前数据库的字符集,将OCI的字符集转换为对应的Oracle数据库的字符集,如果无对应的Oracle数据库的字符集,则默认Oracle数据库的字符集为US7ASCII。
- 存储在Oracle数据库中的字符如果不能转换为GaussDB数据库所支持的编码,通常会被转换为?或¿。如果使用了Oracle数据库无法处理的GaussDB数据库编码,将会产生有一个告警,以及字符将会被替换字符替代。
- 建议GaussDB数据库与Oracle数据库字符集保持一致以保证字符可以被被正常解析,例如:将GaussDB数据库字符集配置为UTF8以及将Oracle数据库字符集配置为AL32UTF8。
- 权限约束
- 禁止使用DATABASE LINK连接初始用户。禁止初始用户进行创建、修改和删除DATABASE LINK对象操作。
- 创建DATABASE LINK权限需要使用GRANT语法赋予,新建用户默认无权限,系统管理员拥有权限。具体请参见《参考》中“SQL参考 > SQL语法 > G > GRANT”章节。
- 当赋予用户创建DATABASE LINK权限时,即默认许可用户使用远程数据库的IP对其进行访问。若不希望存在该情况,请不要使用GRANT对用户赋权。
- 连接约束
- 当未指定CURRENT_USER或CONNECT TO连接串时(即使用当前数据库初始用户名和空的密码连接),会连接失败。
- 非透明多写特性下,使用localhost、127.0.0.1或本机IP及对应端口可连接当前实例数据库。
- DATABASE LINK创建时,不会对其是否可连接成功进行验证,如果缺乏相关的关键字,可能会在使用时报错。
- 如果在创建DATABASE LINK对象后重新生成密钥文件,使用DATABASE LINK时将会报错。因为创建DATABASE LINK时使用的密钥文件与后续解密时使用的密钥文件不一致。
- OPTION选项中conn_opt不支持设置密码且传入的libpq参数不能和原有参数重复。
- 连接Oracle数据库时,OPTIONS选项中max_long和lob_prefetch为预置参数,设置后暂不生效。
- 升级约束
- 元数据和锁相关
- 使用DATABASE LINK对远程表操作时,会在本地创建与远程对应的Schema,若本地不存在该表的元数据信息,会将元数据信息写入本地系统表中,此时会使用7级锁保证写入的一致性,持续到事务结束后释放锁,删除DATABASE LINK时会将相应的元数据信息删除。
- 使用DATABASE LINK时,在本地创建的表仅用于存储远程表的元数据信息,无法通过\d或pg_get_tabledef函数查询该表的结构。
- 如果业务中存在长事务首次使用DATABASE LINK操作远程对象时,会持续持锁直到事务结束,其他首次使用DATABASE LINK的事务会被阻塞。可通过对远程对象进行简单查询操作,使其元数据快速缓存到本地进行规避该情况。另外,远程表结构发生变化时,本地要更新存储的元数据信息,也会有类似阻塞情况。
- 在本地创建与远程对应的Schema时,本地的Schema名称长度上限为63,格式为“[username#]远程Schema@dblink_name”,其中DATABASE LINK为PRIVATE时,username#不可省略。
- 由于部分谓词无法下推,通过DBLINK在使用UPDATE、DELETE及FOR UPDATE功能时,加锁的范围可能会扩大,可通过打印计划查询下推语句判断加锁范围。
- 事务约束
使用DATABASE LINK时,本地事务和远程事务存在以下关系:
- 本地事务会同步控制远程事务的提交/回滚状态。
- 隔离级别的对应关系为如表1、表2所示。
表1 连接非透明多写特性下GaussDB数据库隔离级别对应关系表 本地隔离级别
远程隔离级别
Read Uncommitted
Repeatable Read
Read Committed
Repeatable Read
Repeatable Read
Repeatable Read
Serializable
Serializable
表2 连接Oracle数据库隔离级别对应关系表 本地隔离级别
远程隔离级别
Read Committed
Read Committed
Read Only
Read Only
Serializable
Serializable
本地事务提交过程中会向远程发送事务提交请求,如果远程事务提交成功后出现异常情况导致本地的事务提交失败(如连接异常,本地集群实例异常等情况),远程的事务提交无法被撤回,可能出现本地事务与远程事务不一致的情况。
- 支持SQL范围约束
- DATABASE LINK函数和存储过程调用约束
- 仅在非透明多写特性下支持通过DATABASE LINK连接调用远程函数或者存储过程。
- 通过DATABASE LINK调用远程数据库中的函数时,本地数据库需创建与远程函数名称和参数列表完全一致的函数,若远程函数存在重载,则需要在本地数据库创建对应的所有重载函数,否则会导致参数匹配失败。
- DATABASE LINK调用远程数据库的存储过程和函数时,参数或返回值类型不能包含自定义类型,不支持OUT/INOUT参数或有默认值的参数,并且不能为PACKAGE内函数、聚集函数、窗口函数以及返回集合的函数;不支持使用SELECT * FROM func@dblink();形式调用远程函数。
- PLSQL_BODY内通过DATABASE LINK调用远程数据库的存储过程或函数时,参数或返回值类型不能包含自定义类型,不支持OUT/INOUT参数或有默认值的参数,并且不能为PACKAGE内函数、重载函数、聚集函数、窗口函数以及返回集合的函数。
- DATABASE LINK调用远程数据库的存储过程和函数不指定Schema,默认调用PUBLIC下的函数或存储过程。
- DATABASE LINK调用远程数据库的存储过程和函数时,参数列表不支持通过“:=”或者“=>”的方式为参数赋值。
- PLSQL_BODY内调用远程数据库的存储过程或函数时,应使用[CALL | SELECT] [ schema. ] { func_name@dblink | procedure_name@dblink } ( param_expr )的语法格式调用。
- PLSQL_BODY内调用远程数据库的无参存储过程或函数时,应使用[CALL | SELECT] [ schema. ] { func_name@dblink | procedure_name@dblink } ( )的语法格式调用。
- 同义词约束
- 不支持将DATABASE LINK名创建为一个同义词的使用方法。
- 将使用DATABASE LINK访问的远程对象创建为同名词时,若未指定远程对象的Schema,则默认采用创建同义词的当前Schema作为远程对象的Schema。
- 不支持通过DATABASE LINK调用远程数据库中指向一个DATABASE LINK对象的同义词。例如如下场景:
- 在数据库a(db1)中创建表a(table1)。
- 在数据库b(db2)中创建连接数据库a(db1)的DATABASE LINK对象(dblink1),并创建同义词(CREATE SYNONYM table11 FOR user1.table1@dblink1";)。
- 在数据库c(db3)创建连接数据库b(db2)的DATABASE LINK对象(dblink2),通过dblink2调用数据库b(db2)上的同义词table11(执行SELECT * FROM table11 @dblink2;,会返回“If the remote synonym is a dblink object, dblink access is not supported”的报错信息)。
- 创建同义词的注意事项请参见《参考》中 “SQL参考 > SQL语法 > C > CREATE SYNONYM”章节。
- 连接Oracle数据库时,不支持远程为嵌套同义词。
- 表类型约束
- 视图约束 目前支持对DATABASE LINK的远程表创建视图,当远程表本身的结构发生变化时,该视图使用时会触发视图重编译。例如:
- 在数据库db1中创建表table1。
- 在数据库db2中创建连接数据库db1的DATABASE LINK对象dblink1,并创建视图view1(CREATE VIEW view1 AS SELECT * FROM table1@dblink1;)。
- 在数据库db1中删除表table1的一列,在数据库db2上查询视图view1会重编译该视图,且重编译失败,并产生重编译失败报错。
- 在数据库db1中恢复表table1删除列,在数据库db2上查询视图view1会重编译该视图,且重编译成功,并正常返回查询结果。
- 其他场景
- DATABASE LINK表不支持触发器,包括触发器调用函数内使用DATABASE LINK场景、触发器调用函数为DATABASE LINK函数、在DATABASE LINK上定义触发器等情况。
- 暂不支持UPSERT、MERGE语法。
- 不支持CURRENT CURSOR语法。
- 不支持查询表的隐藏字段。
- 不支持DATABASE LINK访问远端类型。
- DUMP与备份约束
- 不支持DATABASE LINK相关数据库对象的DUMP,备机不支持DATABASE LINK调用。
- 不支持DATABASE LINK相关数据库对象的实例备份后恢复使用。因为不同实例的密钥文件不同,在使用 DATABASE LINK 时需要使用实例密钥文件进行解密。
- JOIN下推约束
- 谓词下推约束
- 仅支持WHERE子句使用数据库内置的数据类型、操作符和函数,并且使用的函数是IMMUTABLE类型。
- 不支持WHERE子句中同时使用到多张表的条件下推。
- 连接Oracle数据库时,不支持WHERE子句包含函数的条件下推。
- 聚集函数下推约束
仅支持单表且没有GROUP子句、ORDER BY子句、HAVING子句、LIMIT子句的SELECT语句,并且不支持窗口函数。
- HINT下推约束
支持针对DATABASE LINK表对象的Hint条件下推,仅限Scan方式的Hint下推,语法格式如下:
[no] tablescan|indexscan|indexonlyscan(table [index])
并要求在一个 queryblock 中的表名或表别名不能重复。
| SQL类型 | 操作对象 | 支持选项说明 | 执行上下文 |
|---|---|---|---|
| 创建DATABASE LINK | DATABASE LINK | - | 普通事务块、存储过程、函数以及高级包。 |
| 修改DATABASE LINK | DATABASE LINK | 仅支持用户名、密码的修改 | 普通事务块、存储过程、函数以及高级包。 |
| 删除DATABASE LINK | DATABASE LINK | - | 普通事务块、存储过程、函数以及高级包。 |
| SELECT语句 | 普通表、普通视图、全量物化视图 |
| 普通事务块、存储过程、函数、高级包以及逻辑视图。 |
| INSERT语句 | 普通表 |
说明:
| 普通事务块、存储过程、函数以及高级包。 |
| UPDATE语句 | 普通表 |
说明: 不支持多表UPDATE操作。 | 普通事务块、存储过程、函数以及高级包。 |
| DELETE语句 | 普通表 |
说明: 不支持多表DELETE操作。 | 普通事务块、存储过程、函数以及高级包。 |
| LOCK TABLE语句 | 普通表 |
| 普通事务块。 |
对于分区表,支持partition子句指定分区。
| SQL类型 | 操作对象 | 支持选项说明 | 执行上下文 |
|---|---|---|---|
| 创建DATABASE LINK | DATABASE LINK | - | 普通事务块、存储过程、函数以及高级包。 |
| 修改DATABASE LINK | DATABASE LINK | - | 普通事务块、存储过程、函数以及高级包。 |
| 删除DATABASE LINK | DATABASE LINK | - | 普通事务块、存储过程、函数以及高级包。 |
| SELECT语句 | 普通表、普通视图、物化视图 |
| 普通事务块、存储过程、函数、高级包以及逻辑视图。 |
| INSERT语句 | 普通表 |
说明:
| 普通事务块、存储过程、函数以及高级包。 |
| UPDATE语句 | 普通表 |
说明:
| 普通事务块、存储过程、函数以及高级包。 |
| DELETE语句 | 普通表 |
说明:
| 普通事务块、存储过程、函数以及高级包。 |
对于分区表,支持partition子句指定分区
| 维度 | GaussDB表类型 | DATABASE LINK支持情况 | |
|---|---|---|---|
| TEMP选项 | 临时表 | 不支持。 | |
| 全局临时表 | 支持。 | ||
| UNLOGGED选项 | 非日志表 | 支持。 | |
| 存储特性 | 行存 | Astore | 支持。 |
| Ustore | 支持。 | ||
| 分区表 | 支持。 | ||
| 二级分区表 | 支持。 | ||
| 视图 | DATABASE LINK访问远程视图 | 支持查询,不支持DML。 | |
| 本地视图通过DATABASE LINK关联远程表 | 支持查询,不支持DML。 | ||
| 维度 | GaussDB表类型 | DATABASE LINK支持情况 | |
|---|---|---|---|
| TEMP选项 | 全局临时表 | 支持 | |
| 存储特性 | 普通表 | 支持 | |
| 分区表 | 支持 | ||
| 二级分区表 | 支持 | ||
| 视图 | DATABASE LINK访问远程视图 | 支持查询,不支持DML。 | |
| 本地视图通过 DATABASE LINK 关联远程表 | 支持查询,不支持DML。 | ||
| Oracle数据类型 | GaussDB对应数据类型 | 增 | 删 | 改 | 查 | ||
|---|---|---|---|---|---|---|---|
| 字符类型 | char | char | bpchar(1) | 是 | 是 | 是 | 是 |
| char(10) | bpchar(10) | 是 | 是 | 是 | 是 | ||
| char(10 byte) | bpchar(10) | 是 | 是 | 是 | 是 | ||
| char(10 char) | bpchar(10) | 是 | 是 | 是 | 是 | ||
| varchar2 (varchar) | varchar2(10) | varchar(10) | 是 | 是 | 是 | 是 | |
| varchar2(10 byte) | varchar(10) | 是 | 是 | 是 | 是 | ||
| varchar2(10 char) | varchar(10) | 是 | 是 | 是 | 是 | ||
| nchar | nchar | text | 是 | 是 | 是 | 是 | |
| nchar(10) | text | 是 | 是 | 是 | 是 | ||
| nvarchar2 | nvarchar2(10) | varchar(10) | 是 | 是 | 是 | 是 | |
| 数值类型 | number | number | numeric(10,3) | 是 | 是 | 是 | 是 |
| number(10) | int8 | 是 | 是 | 是 | 是 | ||
| number(10,3) | numeric(10,3) | 是 | 是 | 是 | 是 | ||
| float | float | numeric | 是 | 是 | 是 | 是 | |
| float(10) | float8 | 是 | 是 | 是 | 是 | ||
| binary_float | binary_float | float4 | 是 | 是 | 是 | 是 | |
| binary_double | binary_double | float8 | 是 | 是 | 是 | 是 | |
| 长类型 | long | long | text | 否 | 否 | 否 | 否 |
| long raw | long raw | bytea | 否 | 否 | 否 | 否 | |
| raw | raw(10) | bytea | 是 | 是 | 是 | 是 | |
| 时间类型 | date | date | timestamp | 是 | 是 | 是 | 是 |
| timestamp | timestamp | timestamp | 是 | 是 | 是 | 是 | |
| timestamp with time zone | timestamptz | 是 | 是 | 是 | 是 | ||
| timestamp with local time zone | timestamptz | 是 | 是 | 是 | 是 | ||
| timestamp(9) | timestamp | 是 | 是 | 是 | 是 | ||
| timestamp(9) with time zone | timestamptz | 是 | 是 | 是 | 是 | ||
| timestamp(9) with localtime zone | timestamptz | 是 | 是 | 是 | 是 | ||
| interval year | interval year to month | interval | 是 | 是 | 是 | 是 | |
| interval year() to month | interval | 是 | 是 | 是 | 是 | ||
| interval day | interval day to second | interval | 是 | 是 | 是 | 是 | |
| interval day to second() | interval | 是 | 是 | 是 | 是 | ||
| interval day() to second | interval | 是 | 是 | 是 | 是 | ||
| interval day() to second() | interval | 是 | 是 | 是 | 是 | ||
| 大对象类型 | blob | blob | bytea | 否 | 否 | 否 | 否 |
| clob | clob | text | 否 | 否 | 否 | 否 | |
使用示例
- 连接GaussDB数据库。
-- DATABASE LINK相关DDL语句。 -- 前置操作。 gaussdb=# CREATE USER jack WITH PASSWORD '********'; CREATE ROLE -- 赋予用户创建DATABASE LINK对象的权限。 gaussdb=# GRANT CREATE PUBLIC DATABASE LINK TO jack; GRANT -- 赋予用户删除DATABASE LINK对象的权限。 gaussdb=# GRANT DROP PUBLIC DATABASE LINK TO jack; GRANT ROLE -- 赋予用户修改DATABASE LINK对象的权限。 gaussdb=# GRANT ALTER PUBLIC DATABASE LINK TO jack; GRANT ROLE -- 回收用户创建DATABASE LINK对象的权限。 gaussdb=# REVOKE CREATE PUBLIC DATABASE LINK FROM jack; REVOKE -- 回收用户删除DATABASE LINK对象的权限。 gaussdb=# REVOKE DROP PUBLIC DATABASE LINK FROM jack; REVOKE ROLE -- 回收用户修改DATABASE LINK对象的权限。 gaussdb=# REVOKE ALTER PUBLIC DATABASE LINK FROM jack; REVOKE ROLE -- 清理环境。 gaussdb=# DROP USER jack; DROP ROLE -- 前置操作。 gaussdb=# CREATE USER local_user WITH SYSADMIN PASSWORD '********'; CREATE ROLE gaussdb=# SET ROLE local_user PASSWORD '********'; SET -- 创建DATABASE LINK对象(host可以是IPV6地址)。 gaussdb=> CREATE PUBLIC DATABASE LINK dblink CONNECT TO 'remote_user' IDENTIFIED BY '********' USING (host '***.***.***.***', port '*****', dbname 'remote_db'); CREATE DATABASE LINK -- 修改DATABASE LINK对象。 gaussdb=> ALTER PUBLIC DATABASE LINK dblink CONNECT TO 'remote_user' IDENTIFIED BY '********'; ALTER DATABASE LINK -- 删除DATABASE LINK对象。 gaussdb=> DROP PUBLIC DATABASE LINK dblink; DROP DATABASE LINK CREATE DATABASE LINK -- 删除DATABASE LINK对象。 gaussdb=> DROP PUBLIC DATABASE LINK dblink; DROP DATABASE LINK -- 清理环境。 gaussdb=> RESET ROLE; RESET gaussdb=# DROP USER local_user; DROP ROLE -- DATABASE LINK具体操作语句。 -- 前置操作。 gaussdb=# CREATE USER local_user WITH SYSADMIN PASSWORD '********'; CREATE ROLE gaussdb=# CREATE USER remote_user WITH SYSADMIN PASSWORD '********'; CREATE ROLE -- 创建远程数据库。 gaussdb=# CREATE DATABASE remote_db; CREATE DATABASE -- 创建测试DATABASE LINK数据库。 gaussdb=# CREATE DATABASE local_db; CREATE DATABASE gaussdb=# \c remote_db remote_db=# SET ROLE remote_user PASSWORD '********'; SET -- 创建普通表。 remote_db=> CREATE SCHEMA remote_user; --非透明多写特性需执行。 CREATE SCHEMA remote_db=> CREATE TABLE remote_tb(f1 int, f2 text, f3 text[]); CREATE TABLE remote_db=> INSERT INTO remote_tb VALUES (0,'a','{"a0","b0","c0"}'); INSERT 0 1 remote_db=> INSERT INTO remote_tb VALUES (1,'bb','{"a1","b1","c1"}'); INSERT 0 1 remote_db=> INSERT INTO remote_tb VALUES (2,'cc','{"a2","b2","c2"}'); INSERT 0 1 -- 创建function。 remote_db=> CREATE OR REPLACE FUNCTION f(a in int, b in int) RETURN int AS tmp int := a + b; BEGIN RETURN tmp; END; / CREATE FUNCTION -- 创建同义词。 remote_db=> CREATE SYNONYM remote_sy FOR remote_tb; CREATE SYNONYM remote_db=> \c local_db local_db=# SET ROLE local_user PASSWORD '********'; SET local_db=> CREATE SCHEMA local_user; --非透明多写特性需执行。 CREATE SCHEMA local_db=> CREATE TABLE local_tb(f1 int, f2 text, f3 text[]); CREATE TABLE local_db=> INSERT INTO local_tb VALUES (2,'c','{"a2","b2","c2"}'); INSERT 0 1 -- 创建DATABASE LINK对象 local_db=> CREATE PUBLIC DATABASE LINK dblink CONNECT TO 'remote_user' IDENTIFIED BY '********' USING (host '***.***.***.***', port '*****', dbname 'remote_db'); CREATE DATABASE LINK -- 查询远程表 local_db=> SELECT * FROM remote_tb@dblink ORDER BY f1; f1 | f2 | f3 ----+----+------------ 0 | a | {a0,b0,c0} 1 | bb | {a1,b1,c1} 2 | cc | {a2,b2,c2} (3 rows) -- 向远程表插入数据。 local_db=> INSERT INTO remote_tb@dblink VALUES (4,'d','{"a1","b2","c3"}'); INSERT 0 1 -- 更新远程表。 local_db=> UPDATE remote_tb@dblink SET f2 = 'aa' WHERE f1 = 0; UPDATE 1 -- 删除远程表数据。 local_db=> DELETE remote_tb@dblink WHERE f1 = 1; DELETE 1 -- 本地表JOIN远程表。 local_db=> SELECT * FROM remote_tb@dblink JOIN local_tb ON local_tb.f1 = remote_tb.f1@dblink; f1 | f2 | f3 | f1 | f2 | f3 ----+----+------------+----+----+------------ 2 | cc | {a2,b2,c2} | 2 | c | {a2,b2,c2} (1 row) -- AGG函数。 local_db=> SELECT count(*) FROM remote_tb@dblink; count ------- 3 (1 row) -- 访问远程函数。 local_db=> SELECT f@dblink(1,2); f --- 3 (1 row) -- PLSQL_BODY内访问远程函数。 local_db=> CREATE OR REPLACE FUNCTION call_f(a in int, b in int) RETURN int AS tmp int; BEGIN tmp := f@dblink(a, b); RETURN tmp; END; / CREATE FUNCTION local_db=> SELECT call_f(1, 2); call_f -------- 3 (1 row) -- 创建DATABASE LINK对象的同义词。 local_db=> CREATE SYNONYM local_sy FOR remote_user.remote_tb@dblink; CREATE SYNONYM local_db=> SELECT * FROM local_sy ORDER BY f1; f1 | f2 | f3 ----+----+------------ 0 | aa | {a0,b0,c0} 2 | cc | {a2,b2,c2} 4 | d | {a1,b2,c3} (3 rows) -- 访问远程数据库的同义词。 local_db=> SELECT * FROM remote_sy@dblink ORDER BY f1; f1 | f2 | f3 ----+----+------------ 0 | aa | {a0,b0,c0} 2 | cc | {a2,b2,c2} 4 | d | {a1,b2,c3} (3 rows) -- DATABASE LINK支持部分Hint下推。 local_db=> EXPLAIN (VERBOSE, COSTS off) SELECT /*+ tablescan(remote_sy) */ * FROM remote_sy@dblink; QUERY PLAN ----------------------------------------------------------------------------------------- Foreign Scan on "remote_user@dblink".remote_tb remote_sy Output: f1, f2, f3 Remote SQL: SELECT /*+ tablescan(remote_tb) */ f1, f2, f3 FROM remote_user.remote_tb (3 rows) -- 查看DATABASE LINK系统表gs_database_link。 local_db=> SELECT dlname,dlowner,options FROM gs_database_link; dlname | dlowner | options --------+---------+--------------------------------------------------- dblink | 0 | {host=***.***.***.***,port=*****,dbname=remote_db} (1 row) -- 查看DATABASE LINK系统视图gs_db_links。 local_db=> START TRANSACTION; START TRANSACTION local_db=> SELECT * FROM remote_sy@dblink ORDER BY f1; f1 | f2 | f3 ----+----+------------ 0 | aa | {a0,b0,c0} 2 | cc | {a2,b2,c2} 4 | d | {a1,b2,c3} (3 rows) local_db=> SELECT intransaction FROM gs_db_links; intransaction --------------- t (1 row) local_db=> END; COMMIT -- 清理环境。 local_db=> \c postgres gaussdb=# DROP DATABASE local_db; DROP DATABASE gaussdb=# DROP DATABASE remote_db; DROP DATABASE gaussdb=# DROP USER local_user; DROP ROLE gaussdb=# DROP USER remote_user; DROP ROLE
- 连接Oracle数据库。
-- Oracle库创建普通表。 SQL> CREATE USER oracle_user IDENTIFIED BY ********; SQL> GRANT CREATE TABLE TO oracle_user; SQL> GRANT SELECT ANY TABLE TO oracle_user; SQL> GRANT SELECT ANY DICTIONARY TO oracle_user; SQL> GRANT RESOURCE TO oracle_user; SQL> GRANT CREATE SYNONYM TO oracle_user; SQL> GRANT CREATE TABLESPACE TO oracle_user; SQL> GRANT CREATE SESSION TO oracle_user; SQL> ALTER USER oracle_user QUOTA 100M ON users; SQL> CONN oracle_user/********@***.***.**.**:****/orcl SQL> CREATE TABLE remote_tb(f1 int, f2 varchar(10), f3 varchar(20)); SQL> INSERT INTO remote_tb VALUES (0,'a','{"a0","b0","c0"}'); SQL> INSERT INTO remote_tb VALUES (1,'bb','{"a1","b1","c1"}'); SQL> INSERT INTO remote_tb VALUES (2,'cc','{"a2","b2","c2"}'); -- 创建同义词。 SQL> CREATE SYNONYM remote_sy FOR remote_tb; SQL> COMMIT; -- DATABASE LINK相关DDL语句。 -- 前置操作。 gaussdb=# CREATE USER jack WITH PASSWORD '********'; CREATE ROLE -- 赋予用户创建DATABASE LINK对象的权限。 gaussdb=# GRANT CREATE PUBLIC DATABASE LINK TO jack; GRANT -- 赋予用户删除DATABASE LINK对象的权限。 gaussdb=# GRANT DROP PUBLIC DATABASE LINK TO jack; GRANT ROLE -- 赋予用户修改DATABASE LINK对象的权限。 gaussdb=# GRANT ALTER PUBLIC DATABASE LINK TO jack; GRANT ROLE -- 回收用户创建DATABASE LINK对象的权限。 gaussdb=# REVOKE CREATE PUBLIC DATABASE LINK FROM jack; REVOKE -- 回收用户删除DATABASE LINK对象的权限。 gaussdb=# REVOKE DROP PUBLIC DATABASE LINK FROM jack; REVOKE ROLE -- 回收用户修改DATABASE LINK对象的权限。 gaussdb=# REVOKE ALTER PUBLIC DATABASE LINK FROM jack; REVOKE ROLE -- 清理环境。 gaussdb=# DROP USER jack; DROP ROLE -- 前置操作。 gaussdb=# CREATE USER local_user WITH sysadmin PASSWORD '********'; CREATE ROLE gaussdb=# SET ROLE local_user PASSWORD '********'; SET -- 创建DATABASE LINK对象,orcl是Oracle库实例名称。 gaussdb=> CREATE PUBLIC DATABASE LINK dblink CONNECT TO 'oracle_user' IDENTIFIED BY '********' OCI USING (dbserver '***.***.***.***:****/orcl', case_insensitive 'on'); CREATE DATABASE LINK -- 修改DATABASE LINK信息。 gaussdb=> ALTER PUBLIC DATABASE LINK dblink CONNECT TO 'oracle_user' IDENTIFIED BY '********' USING (time_out '0'); ALTER DATABASE LINK -- 删除DATABASE LINK对象。 gaussdb=> DROP PUBLIC DATABASE LINK dblink; DROP DATABASE LINK -- 清理环境。 gaussdb=> RESET ROLE; RESET gaussdb=# DROP USER local_user; DROP ROLE -- DATABASE LINK具体操作语句。 -- 前置操作。 gaussdb=# CREATE USER gauss_user WITH SYSADMIN PASSWORD '********'; CREATE ROLE gaussdb=# CREATE DATABASE local_db; --测试DATABASE LINK数据库。 CREATE DATABASE gaussdb=# \c local_db local_db=# SET ROLE gauss_user PASSWORD '********'; SET local_db=> CREATE TABLE local_tb(f1 int, f2 text, f3 text[]); CREATE TABLE local_db=> INSERT INTO local_tb VALUES (2,'c','{"a2","b2","c2"}'); INSERT 0 1 local_db=> CREATE PUBLIC DATABASE LINK dblink CONNECT TO 'oracle_user' IDENTIFIED BY '********' OCI USING (dbserver '***.***.***.***:****/orcl', case_insensitive 'on'); -- host和port需要根据实际情况填写。 CREATE DATABASE LINK -- 查询远程表。 local_db=> SELECT * FROM remote_tb@dblink ORDER BY f1; f1 | f2 | f3 ----+----+------------------ 0 | a | {"a0","b0","c0"} 1 | bb | {"a1","b1","c1"} 2 | cc | {"a2","b2","c2"} (3 rows) -- 向远程表插入数据。 local_db=> INSERT INTO remote_tb@dblink VALUES (4,'d','{"a1","b2","c3"}'); INSERT 0 1 -- 更新远程表。 local_db=> UPDATE remote_tb@dblink SET f2 = 'aa' WHERE f1 = 0; UPDATE 1 -- 删除远程表数据。 local_db=> DELETE remote_tb@dblink WHERE f1 = 1; DELETE 1 -- 本地表JOIN远程表。 local_db=> SELECT * FROM remote_tb@dblink JOIN local_tb ON local_tb.f1 = remote_tb.f1@dblink; f1 | f2 | f3 | f1 | f2 | f3 ----+----+------------------+----+----+------------ 2 | cc | {"a2","b2","c2"} | 2 | c | {a2,b2,c2} (1 row) -- AGG函数。 local_db=> SELECT count(*) FROM remote_tb@dblink; count ------- 3 (1 row) -- 创建DATABASE LINK对象的同义词。 local_db=> CREATE SYNONYM local_sy FOR oracle_user.remote_tb@dblink; CREATE SYNONYM local_db=> SELECT * FROM local_sy ORDER BY f1; f1 | f2 | f3 ----+----+------------------ 0 | aa | {"a0","b0","c0"} 2 | cc | {"a2","b2","c2"} 4 | d | {"a1","b2","c3"} (3 rows) -- 访问远程数据库的同义词。 local_db=> SELECT * FROM remote_sy@dblink ORDER BY f1; f1 | f2 | f3 ----+----+------------------ 0 | aa | {"a0","b0","c0"} 2 | cc | {"a2","b2","c2"} 4 | d | {"a1","b2","c3"} (3 rows) local_db=> EXPLAIN (VERBOSE, COSTS off) SELECT /*+ tablescan(remote_sy) */ * FROM remote_sy@dblink; QUERY PLAN --------------------------------------------------------------------------------------------------------- Foreign Scan on "ORACLE_USER@dblink"."REMOTE_TB" remote_sy Output: f1, f2, f3 Oracle query: SELECT /*2fb321229639e3b7*/ r1."F1", r1."F2", r1."F3" FROM "ORACLE_USER"."REMOTE_TB" r1 Oracle plan: SELECT STATEMENT Oracle plan: TABLE ACCESS FULL REMOTE_TB (5 rows) -- 查看DATABASE LINK系统表gs_database_link。 local_db=> SELECT dlname,dlowner,options FROM gs_database_link; dlname | dlowner | options --------+---------+--------------------------------------------------------- dblink | 0 | {dbserver=***.***.***.***:****/orcl,case_insensitive=on} (1 row) -- 查看DATABASE LINK系统视图gs_db_links。 local_db=> START TRANSACTION; START TRANSACTION local_db=> SELECT * FROM remote_sy@dblink ORDER BY f1; f1 | f2 | f3 ----+----+------------------ 0 | aa | {"a0","b0","c0"} 2 | cc | {"a2","b2","c2"} 4 | d | {"a1","b2","c3"} (3 rows) local_db=> SELECT intransaction FROM gs_db_links; intransaction --------------- t (1 row) local_db=> END; COMMIT -- 清理环境。 local_db=> \c postgres gaussdb=# DROP DATABASE local_db; DROP DATABASE gaussdb=# DROP USER gauss_user; DROP ROLE