使用DBLink过程中遇到的问题有哪些
这篇文章给大家分享的是有关使用DBLink过程中遇到的问题有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站设计、网站建设、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的通川网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
1. 创建DBLink
1.1创建命令
create database link zlbak connect to zlbak01 identified by his using 'orcl';
注意,引号里的orcl,是在数据库服务器配置好的服务名,不是客户端本机配置的。
1.2名称
如果参数global_names为True,则要求创建的DBLink名称必须与被连接库的global_name相同。
create database link orcl connect to zlbak01 identified by his using 'orcl';
被连接的库,global_name可能很长,例如:
select * from global_name;
ORCL.REGRESS.RDBMS.DEV.US.ORACLE.COM
可以通过下面的命令将名称改短,去掉点后面的字符。
update global_name set global_name = 'orcl';
注意,千万不能改为空,否则会造成数据库无法启动,需要用特殊的方法才能解决。
如果通过下面这种方法修改,之前有域名的话,修改后仍然会有点后名的域名。
alter database rename global_name to orcl
当global_names为True时,如果要建多个DBLink指向同一个库,不能重名,怎么办呢?
create database link orcl@link1 connect to zlbak01 identified by his using 'orcl';
create database link orcl@link2 connect to zlbak01 identified by his using 'orcl';
原来,需要在GLOBAL_NAME后面加上@再加上一个标识。
既然global_names为True时这么麻烦,是否可以改为false呢?
如果不用流复制的话,完全是可以的,修改方法:
alter system set global_name=false;
修改后重新启动数据库设置才能生效,改成false之后,DBLink的名称就可以随意取了。
1.3特殊案例
记得是在2014年,做第一家用户的历史数据转出,完成之后,准备通过DBLink来实现远程历史库的查询,遇到一个奇怪的问题。
通过下面的命令创建的DBLink:
create database link zlbak connect to zlbak01 identified by his using 'orcl';
注意,引号里的orcl,是在数据库服务器配置好的服务名,不是客户端本机配置的。
创建好之后,无法正常使用,执行查询报错:
select * from 人员表@zlbak
ORA-12543:TNS:无法连接目标主机。
在服务器上,用tnsping服务名orcl是通的。
在sqlplus中通过zlbak01用户连接orcl也可以正常登录。
用户环境是10.2.0.5 windows 64bit。
弄了一个晚上,最后改成下面这种方式才成功了。
create database link
zlbak connect to zlbak01 identified by his using
'(DESCRIPTION = (ADDRESS_LIST=
(ADDRESS=(PROTOCOL=TCP)
(HOST=192.1.68.1.1)(PORT=1521)))
(CONNECT_DATA=(SERVICE_NAME=orcl)))';
2. 通过DBLink查询远程数据
2.1不支持查询含有LOB类型字段的远程表
当远程表含有blob,clob,xmltype,long等大数据类型字段时,通过DBLink查询会报错:
ORA-22992:无法使用从远程表选择的 LOB定位器
目前已知的两种做法:
a. 对象表加函数转换
源端
1) 创建OBJECT类型,字段跟原表相同,只是把LOB字段改为Varchar2(4000)
2) 以该类型再创建一个Table类型
3) 创建一个读取转换函数,将原表的数据,插入到Table类型中并返回
以游标循环方式,用dbms_lob.getlength和dbms_lob.substr,每次最多取4000个字符,用Pipe Row管道函数输出,需要用自治事务,函数返回前提交事务。
4) 创建一个视图,调用该函数,并以Table语句转换为二维表。
目标端
1) 定义与源端相同的OBJECT类型和Table类型
2) 创建一个接收转换函数,把从源端接收到的Varchar2(4000)拼接后转换为LOB类型。
需要用到自治事务
3) 创建一个视图,通过DBLink查询数据,通过上一步创建的函数转换为LOB字段。
4) 查询这个视图,就像查询表的数据一样,可以正常返回LOB字段数据。
这种方法虽然能够实现,但是由于视图加函数方式,无法利用索引,所以,只能做为临时性的查询手段,并且实现起来比较麻烦。
b. 临时表
虽然不支持直接通过DBLink方式查询LOB类型的字段,但是insert into ……Select方式是支持的。所以,可以在本地服务器创建一个临时表,将查询的远程数据表的数据插入到临时表,然后,通过临时表就可以正常访问到含有LOB类型字段的表了。
这种方式实现起来比“对象表加转换函数”简单得多,重要的是可以用到索引。
2.2通过driving_site来指定驱动表
很多技术人员在用户环境中,通过DBLink来关联查询一些业务系统的远程数据表,但是,可能大多数人并没有注意到一个问题:远程数据表的全表复制。
你可能以为它会像本地表一样用到索引,实际上,很可能根本就没有用到索引,不信你可以马上看看那些SQL的执行计划,注意分析其中操作为Remote的行,那就是全表复制。
访问远程数据表时,如果在索引相关字段的查询条件中直接指定了值,则可以直接利用索引。
例如:
Select id from H病人医嘱记录 where 病人id=:v1;
其中” H病人医嘱记录”是一个通过DBLink连接到远程数据库表的视图。
但是,以下几种常见情况,是没有利用远程表的索引的:
1) 本地表和远程表的连接
2) Table内存表和远程表的连接
3) 索引相关的查询条件用到了Or
例如:
Select b.Id, b.类别, c.名称 As 类别名称, b.名称, b.标本部位
From H病人医嘱记录 A, 诊疗项目目录 B, 诊疗项目类别 C,
Table(f_Num2list('43190722, 43190723')) D
Where a.Id = d.Column_Value And a.诊疗项目id = b.Id And b.类别 = c.编码
这种情况,会将远程数据表的全部数据查询后传输到本地服务器,再进行表间连接。
当远程表是大表,本地表是小表,关联查询时,需要决定数据复制的方向,这是分布式数据访问都存在的一个问题。
在Select后加提示字/*+driving_site(a)*/这种方式可以指定远程表为驱动表,把本地的小表复制到远程,这样就可以用到索引了,并且避免了复制大表数据到本地服务器。
但是,如果含有Table内存表这种情况,还是无法利用索引,因为内存表的数据不支持作为被驱动表复制到远程,可以改写查询,避免使用Table方式。例如,用in方式,直接将条件值传入,带来的问题是无法使用绑定变量,对于历史数据查询这种低频业务,不使用绑定变量是可以接受的。
注意,driving_site对dml无效(insert,delete,update),dml以目标表所在库驱动SQL计划。
还有下面这种情况,虽然都是远程表连接,但是因为使用了Or,导致执行计划没有使用索引,可以调整为将Or展开,写成Union All方式。
Select Distinct b.发送号, b.发送人 As 人员, b.发送时间 As 时间
From H病人医嘱记录 A, H病人医嘱发送 B
Where a.Id = b.医嘱id And (a.Id = 43895356 Or a.相关id = 43895356)
Order By 时间 Desc, 发送号
2.4查询DBLink后需要关闭连接
通过db-link执行查询后,当前session到远程数据库的连接是不会自动关闭的,在基于连接池的管理中可能会引起目标数据库的Session泛滥,从而消耗进程资源。
这种情况下,可以在查询完成之后执行关闭连接命令:
alter sesssion close database link orcl;
注意需要先执行commit命令。也可以使用系统包来关闭连接:
DBMS_SESSION.CLOSE_DATABASE_LINK(orcl);
2.5提交事务
在使用PL/SQL developer里面通过dblink执行查询后,
commit和rollback会亮,是什么原因呢?
下面的测试可以发现一些规律:
select count(1) from test@dblink;
不会产生commit提示
select * from test@dblink;
会产生commit提示
select * from test@dblink where rownum<5;
不会产生commit提示
原来,当需要的数据都返回了,就不会产生commit提示,否则就会产生commit提示。
通过下面的语句,可以查到回滚段的情况:
Select s.Sid, s.Serial#, s.Sql_Hash_Value,
r.Segment_Name, t.Xidusn, t.Xidslot, t.Xidsqn
From V$session S, V$transaction T, Dba_Rollback_Segs R
Where s.Taddr = t.Addr And t.Xidusn = r.Segment_Id(+);
3.其他
3.1以下两个参数可以调整打开的DBLink数量。
open_links :每个session最多允许的dblink数量;
open_links_per_instance:指每个实例最多允许的dblink个数
当前打开的DBLink可以查询视图v$dblink。
3.2通过DBLink插入数据到远程数据库
含有XMLType等对象类型或用户定义类型字段的表,不支持将通过DBLink插入到远程数据库。
所以,直接将要转移的历史数据通过DBLink插入到远程历史库,有些表是不支持的。
3.3不支持通过DBLink执行DDL语句
这个比较可以理解,必竟修改数据结构,涉及到的关联处理太多,例如并发控制等。
感谢各位的阅读!关于“使用DBLink过程中遇到的问题有哪些”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
当前文章:使用DBLink过程中遇到的问题有哪些
分享URL:http://azwzsj.com/article/jhidii.html