在几天前说过关于db link分配权限的问题,当时也折磨了我好一会儿
http://blog.itpub.net/23718752/viewspace-1869425/
大体的情况还是在118的服务器中去访问128中的某个表的时候存在一些访问的问题,最后是重建了一个public的db link得以修复,当时对于这个问题的临时处理也是一波三折,还触发了一个oracle的bug,也算是有惊无险。
但是对于之前操作中的疑问在解释之后统一进行解答。
第二天的时候,开发的同事反馈说线上进行测试提dblink不到,这个解释听起来很模糊,到底是不是问题自己感觉还有待确认,于是向开发同学了解更多细节。
开发的同学提供的信息如下:
程序访问的时候报错:nested exception is java.sql.SQLException: ORA-24777: use of non-migratable database link not allowed
麻烦看一下是不是database link的问题
对于这个错误,看起来是比较陌生的,自己首先查看了数据库日志层面没有发现任何的报错。说明这个问题的报错应该仅仅是客户端中可能会存在。
为了更进一步明确问题,我尝试从开发那边了解到底是什么样的语句触发了这样一个问题,他们回复说就是一个简单的查询,拿到的语句为:
select count(CN) from TESTORE_LOG where CN = '586480450' and BUY_TIME >= to_date('2015-12-02 00:00:00', 'yyyy-mm-dd hh24:mi:ss') order by BUY_TIME desc
自己也测试了一下,得到的执行计划如下:
> explain plan for select count(CN) from TESTORE_LOG where CN = '586480450' and BUY_TIME >= to_date('2015-12-02 00:00:00', 'yyyy-mm-dd hh24:mi:ss') order by BUY_TIME desc;
> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2100402862
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |
------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT REMOTE | | 1 | 32 | 2 (0)| 00:00:01 | |
| 1 | SORT AGGREGATE | | 1 | 32 | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| TESTORE_LOG | 1 | 32 | 2 (0)| 00:00:01 | GCDB |
|* 3 | INDEX RANGE SCAN | IND_TESTORE_LOG_BTIME | 2 | | 1 (0)| 00:00:01 | GCDB |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("A1"."CN"='586480450')
3 - access("A1"."BUY_TIME">=TO_DATE('2015-12-02 00:00:00', 'yyyy-mm-dd hh24:mi:ss'))
Note
-----
- fully remote statement
其中标黄的部分也是亮点,这个testore_log是通过db link来间接访问的。但是从执行计划来看访问肯定是没有问题的,而且走了索引,效率应该也不会差多少。
自己也切换到指定的用户下,执行了同样的语句,已经能够说明目前的情况下通过sqlplus是没有问题的。
自己也在怀疑是否是public的db link是否存在一些问题,不支持一些使用场景。
于是在mos上查了一圈,发现有一篇文章还是很符合的。
Error "ORA-24777: Use Of Non-Migratable Database Link Not Allowed" Using Oracle XA Datasource When Executing a Select via Database Link. (Doc ID 879543.1)
对于这个问题在10g版本中确实存在,而且workaround是把专用服务器模式改为共享服务器模式。
从目前我的了解来看,为了这个问题修改连接模式还是一个需要谨慎的操作,尤其是核心库,这种操作牵一发而动全身,没有全面的测试是不敢提前出手的。
所以我开始琢磨起这个语句来,看看能不能找出别的思路,所幸的是,这个查询是一个单表的查询,所以还是有机会把这部分功能单独挪到本地,而且如果执行频繁,老在远端做这个操作感觉也是怪怪的。
于是我就给他们做了详细的解释,然后建议他们把这个查询的操作挪到128的服务器上去,没想到谈得还很顺利,一些权限的事情我都能够cover,所以把这个访问入口调整到128的服务器上之后,再没有反馈过这类的错误了。
但是问题虽然解决了,我对于db link还是存在着一些疑问,简单总结一下。
##问题1 起初查看all_synonyms没有得到任何结果,而使用dba_synonyms就可以查出来,
sys@TEST> select * from all_synonyms where owner='APP_TE_FLOW_128' and synonym_name=upper('testore_log');
no rows selected
其实不光是这个128的用户查不出来,使用sysdba查看all_synonyms也是一样的效果。
> select *from all_synonyms where db_link is not null;
no rows selected
可以再稍微扩展一下,如果查看dba_objects,各种类型的对象,只有db link是object_id为null的,最有范儿
>select object_type,count(*)from dba_objects where object_id is null group by object_type;
OBJECT_TYPE COUNT(*)
------------------- ----------
DATABASE LINK xxx
##问题2
在查看表数据的时候,使用current_schema来切换是没有问题的,但是使用db link似乎还是会碰到一些意料之外的问题。
> alter session set current_schema=APP_TE_FLOW_128;
Session altered.
尝试得到表结构信息,竟然报错了,说明还是可以访问,只是最终访问不通。
sys@TEST> desc testore_log
ERROR:
ORA-04043: object "TEST"."testore_log" does not exist
ORA-02063: preceding line from GCDB
这个时候,如果使用对应的用户来查看,这个问题就不会存在,所以current_schema的操作还是在db link使用中受限。而不是最开始推理得出的db link的密码错误。
说到这个,再提一个低级错误,就是使用下面的方式,创建出的db link名字就是APP_TE_FLOW_128.GC_NEW_LINK而不是位于用户APP_TE_FLOW_128下。
CREATE DATABASE LINK APP_TE_FLOW_128.GC_NEW_LINK CONNECT TO FLOW0 IDENTIFIED BY VALUES 'BCF5E83CF6EF0269' USING 'TEST_TEST_CENTER'
##问题3
如果不知道密码,使用identified by values这种方式创建db link.
CREATE DATABASE LINK APP_TE_FLOW_128.GC_NEW_LINK CONNECT TO FLOW0 IDENTIFIED BY VALUES 'BCF5E83CF6EF0269' USING 'TEST_TEST_CENTER'
就很可能触发一个oracle的bug,可能查询时间极长,而且风险极大。
sys@TEST> select count(*)from test_20151208@APP_TE_FLOW_128.GC_NEW_LINK;
select count(*)from test_20151208@APP_TE_FLOW_128.GC_NEW_LINK
*
ERROR at line 1:
ORA-00600: internal error code, arguments: [kzdlk_zt2 err], [18446744073709551603], [], [], [], [], [], []
##问题4
为什么118的服务器端使用db link,发现118的服务器中存在一个同义词。
sys@TEST> select table_name,table_type from cat@gcdb;
TABLE_NAME TABLE_TYPE
------------------------------ -----------
USER_POINT SYNONYM
这个地方其实确实是用到了db link,不过是使用到了public的db link,然后问题又来了,为什么会用到public db link而普通的db link不可以呢,这个其实就是第2个问题的解答,因为我使用了alter session set current_schema=xxx尝试做切换,以为切换过来了,其实没有,这个时候其实还是使用public db link在做查询。
而且db link确实还会有一定的限制,触发一些bug,对于这类问题,想必大家都碰到不少了,所以对于db link的使用还是建议需要尽量减少甚至不用。