oracle 11g dblink 查询的bug --10053用处

解决Oracle 11g中外网通过DBLink访问内网数据库时出现的SQL查询问题。原始SQL在外网无法正常获取数据,通过调整SQL结构并使用子查询的方式解决了这一问题。调整后的SQL在外网成功执行。

   在oracle11g上,外网建的dblink访问内网,好奇怪的SQL,问题SQL在内网是可以的,在外网查不出数据。做为实验,把内网的数据同步到外网,然后查询,是可以的。最后通过调整SQL写法解决了问题。

问题SQL:

SELECT T.P_TYPE_CODE,

 

       T.TYPE_CODE TYPE_ID,
       T.TYPE_NAME,
        TYPE_CODE,
       0 STANDARD_CENT,
       '' REMARK,
       '' STD_COUNT,
       N.IS_CHECK
  FROM gg_SAFE_C_TYPE_NW T, gg_C_STANDARD_NW N
 WHERE T.TYPE_CODE = N.CHECK_NUMBER(+)
 START WITH T.TYPE_ID = '0'
CONNECT BY PRIOR T.TYPE_CODE = T.P_TYPE_CODE

 

       AND T.PROJECT_TYPE IN (1, 3);

 

调整后:       

 

select TT.P_TYPE_CODE,
       TT.TYPE_CODE TYPE_ID,
       TT.TYPE_NAME,
       TT.TYPE_CODE TYPE_CODE,
       0 STANDARD_CENT,
       '' REMARK,
       '' STD_COUNT,
       N.IS_CHECK
  from (SELECT *
          FROM gg_SAFE_C_TYPE_NW T
         START WITH T.TYPE_ID = '0'
        CONNECT BY PRIOR T.TYPE_CODE = T.P_TYPE_CODE
               and PROJECT_TYPE IN (1, 3)) TT,
       gg_C_STANDARD_NWN

 

 WHERE TT.TYPE_CODE = N.CHECK_NUMBER(+);

 

在外网的机器上做了10053,发现问题SQL经过查询转换后是错误的。

问题SQL查询转换后的结果,执行报错

 

SELECT "A1"."P_TYPE_CODE" "P_TYPE_CODE",
       "A1"."TYPE_CODE" "TYPE_ID",
       "A1"."TYPE_NAME" "TYPE_NAME",
       "A1"."TYPE_CODE" "TYPE_CODE",
       0 "STANDARD_CENT",
       '' "REMARK",
       '' "STD_COUNT",
       "A1"."IS_CHECK" "IS_CHECK"
  FROM ((SELECT "A4"."PROJECT_TYPE" "T_$$_PROJECT_TYPE",
                "A4"."P_TYPE_CODE"  "T_$$_P_TYPE_CODE",
                "A4"."TYPE_CODE"    "T_$$_TYPE_CODE",
                "A3"."CHECK_NUMBER" "N_$$_CHECK_NUMBER",
                "A3"."IS_CHECK"     "N_$$_IS_CHECK",
                "A4"."TYPE_CODE"    "TYPE_CODE",
                "A4"."TYPE_NAME"    "T_$$_TYPE_NAME"
           FROM "gg_c_TYPE_NW"@TO_aaa     "A4",
                "gg__STANDARD_NW"@TO_aaa "A3"
          WHERE "A4"."TYPE_CODE" = "A3"."CHECK_NUMBER"(+)
            AND "A4"."TYPE_ID" = '0') UNION ALL
        (SELECT "A6"."PROJECT_TYPE" "T_$$_PROJECT_TYPE",
                "A6"."P_TYPE_CODE"  "T_$$_P_TYPE_CODE",
                "A6"."TYPE_CODE"    "T_$$_TYPE_CODE",
                "A5"."CHECK_NUMBER" "N_$$_CHECK_NUMBER",
                "A5"."IS_CHECK"     "N_$$_IS_CHECK",
                "A6"."TYPE_CODE"    "TYPE_CODE",
                "A6"."TYPE_NAME"    "T_$$_TYPE_NAME"
           FROM "LCAMTEST"."connect$_by$_pump$_003"               "A7",
                "gg_C_TYPE_NW"@TO_aaa     "A6",
                "gg_C_STANDARD_NW"@TO_aaa "A5"
          WHERE "A6"."TYPE_CODE" = "A5"."CHECK_NUMBER"(+)
            AND "A7"."PRIOR T.TYPE_CODE " = "A6"."P_TYPE_CODE"
            AND ("A6"."PROJECT_TYPE" = 1 OR "A6"."PROJECT_TYPE" = 3))) "A1";

 

 

 

调整后的SQL,结果正确            

SELECT "A2"."P_TYPE_CODE" "P_TYPE_CODE",
       "A2"."TYPE_CODE" "TYPE_ID",
       "A2"."TYPE_NAME" "TYPE_NAME",
       "A2"."TYPE_CODE" "TYPE_CODE",
       0 "STANDARD_CENT",
       '' "REMARK",
       '' "STD_COUNT",
       "A1"."IS_CHECK" "IS_CHECK"
  FROM (SELECT "A8"."P_TYPE_CODE" "P_TYPE_CODE",
               "A8"."TYPE_CODE"   "TYPE_CODE",
               "A8"."TYPE_NAME"   "TYPE_NAME"
          FROM "PS_CSG_SAFE_CHECK_TYPE_NW"@TO_LCAM_ZCDEVELOP "A8"
         START WITH "A8"."TYPE_ID" = '0'
        CONNECT BY "A8"."P_TYPE_CODE" = PRIOR "A8"."TYPE_CODE"
               AND ("A8"."PROJECT_TYPE" = 1 OR "A8"."PROJECT_TYPE" = 3)) "A2",
       "PS_CSG_SAFE_CHECK_STANDARD_NW"@TO_LCAM_ZCDEVELOP "A1"
 WHERE "A2"."TYPE_CODE" = "A1"."CHECK_NUMBER"(+);

 

 

 

 

 

 

 

 

 

<think> 我们正在处理用户关于“帆软调用Oracle dblink报错ORA-16000”的查询。根据提供的引用,我们可以总结出两个主要场景: 引用[1]:在查询dblink关联的视图时,因为备节点(DG库)是只读的,当基表结构改变后,视图需要重新编译(写操作),导致ORA-04045和ORA-16000错误。 引用[2]:在只读的物理备库(Physical Standby)上创建物化视图时,因为物化视图的快速刷新需要写物化视图日志(MVIEW LOG),而备库是只读的,所以报错ORA-16000。 用户的问题场景是:帆软报表通过DBLINK访问Oracle数据库时遇到ORA-16000错误。结合引用,我们可以推断,帆软调用的DBLINK可能指向了Oracle的只读备库(例如Data Guard的物理备库),而当需要执行写操作(如重新编译视图或创建物化视图日志)时,就会触发此错误。 解决方案思路: 1. 确认DBLINK指向的是主库还是备库。如果是备库,且备库是只读的,那么任何需要写操作的动作都会失败。 2. 检查帆软报表中使用的SQL语句是否涉及需要写操作的对象(如视图重新编译、物化视图刷新等)。 3. 考虑将DBLINK指向主库(如果允许),因为主库是可读写的,可以执行必要的DDL或DML操作。 具体步骤: 根据引用[1]的案例,当基表结构改变后,视图需要重新编译。在备库上由于只读,无法编译,因此出现错误。解决办法是: - 在主库上重新编译视图,然后备库会自动同步(但注意:备库上自动同步的视图编译操作实际上是在主库上做的,备库只接收重做日志并应用,所以备库上的视图状态会同步为主库编译后的状态)。但是,如果应用直接连接备库,并且在备库上执行查询时发现视图无效,那么备库无法自行编译(因为只读),所以需要确保在主库上编译成功,并且备库应用了这些DDL更改。 - 如果问题仍然存在,可能需要重建DBLINK使其指向主库。 根据引用[2],在只读备库上创建物化视图会失败,因为需要写物化视图日志。因此,如果帆软报表中涉及创建或刷新物化视图,那么必须将DBLINK指向主库。 建议的解决方案: 1. 确认DBLINK指向的数据库是主库还是备库。如果是备库,且报表中的操作需要写权限,则应该修改DBLINK指向主库。 2. 如果必须使用备库(例如为了读写分离,减轻主库压力),那么需要避免任何会导致写操作的动作。例如: - 确保所有对象(视图、同义词等)都是最新的,不需要在备库上重新编译。 - 避免在备库上创建或刷新物化视图。 3. 如果错误是由于视图无效需要重新编译引起的,可以在主库上手动编译视图,然后确保备库已经同步。在备库上,可以通过以下方式检查视图状态并尝试(尽管备库只读,但可以通过主库的同步来更新): - 在主库上编译视图:`ALTER VIEW <view_name> COMPILE;` - 等待同步到备库后,在备库上检查视图状态:`SELECT OBJECT_NAME, STATUS FROM USER_OBJECTS WHERE OBJECT_TYPE='VIEW' AND STATUS='INVALID';` - 如果视图在备库上仍然无效,可能是因为主库的DDL在备库应用时没有自动编译(因为备库只读,不能执行编译),那么可能需要重建视图(在主库上重建,然后同步到备库)。 4. 如果报表中使用了物化视图,并且需要快速刷新,那么必须将DBLINK指向主库,因为物化视图日志的维护需要写操作。 对于帆软调用DBLINK报错ORA-16000,我们可以总结为:目标数据库是只读的,而操作需要写权限。因此,最直接的解决方案是修改DBLINK,使其指向可读写的主库。 如果用户不能修改DBLINK指向主库(例如,由于高可用或负载均衡的要求),那么需要检查并修改报表中的SQL,确保不会触发任何写操作。例如: - 避免在查询使用需要重新编译的无效视图(确保视图有效)。 - 避免在只读库上创建或刷新物化视图。 另外,ORA-16000错误的官方解释是:数据库打开为只读模式,无法执行写操作。因此,任何试图写入的操作都会导致此错误。 结论:首先检查帆软报表中使用的SQL是否包含任何会导致写操作的动作(如编译视图、维护物化视图日志等)。如果存在,那么将DBLINK指向主库是最直接的解决方案。 如果用户无法修改DBLINK指向,那么需要调整报表逻辑,避免在只读备库上执行需要写权限的操作。 由于用户问题描述为“帆软调用Oracle dblink报错ORA-16000”,我们可以直接建议用户检查DBLINK指向的数据库是否为只读备库,并尝试将DBLINK指向主库。 如果用户需要进一步诊断,可以提供具体的SQL语句,以便分析是否包含写操作。 注意:引用中提到的两个场景(视图重新编译和物化视图)都是导致ORA-16000的常见原因。 因此,回答如下: </think>### 帆软调用Oracle dblink报错ORA-16000的解决方案 该错误通常发生在帆软通过DBLINK访问**Oracle只读备库(如Data Guard物理备库)** 时,因备库禁止写操作导致。以下是根本原因和解决方案: #### 错误原因分析 1. **只读库限制** ORA-16000错误直接表明目标数据库处于`READ ONLY`模式,禁止执行任何写操作[^1][^2]。 2. **DBLINK指向备库** 帆软配置的DBLINK可能指向了Oracle Data Guard的**物理备库**(而非主库)[^1]。 3. **对象编译/维护需求** 当基表结构变更时,依赖对象(视图/物化视图)需重新编译,但备库无法执行`ALTER...COMPILE`等DDL操作[^1]。 4. **物化视图刷新机制** 快速刷新(REFRESH FAST)需在源库写入物化视图日志(MVIEW LOG),而备库禁止DML操作[^2]。 #### 解决方案 1. **修改DBLINK指向主库** ```sql -- 检查当前DBLINK配置 SELECT * FROM ALL_DB_LINKS; -- 重建DBLINK指向主库(示例) CREATE DATABASE LINK FR_LINK CONNECT TO username IDENTIFIED BY password USING '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=primary_host)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=primary_sid)))'; ``` **关键点**:确保`HOST`参数为主库地址。 2. **避免在备库执行写操作** - 禁用视图自动编译:在帆软报表中避免使用复杂视图,改用直接基表查询 - 取消物化视图快速刷新:若需同步数据,改用`REFRESH COMPLETE`(全量刷新)或调整ETL策略 ```sql -- 创建全量刷新物化视图(在可写库执行) CREATE MATERIALIZED VIEW mv_sales REFRESH COMPLETE AS SELECT * FROM sales@primary_db; ``` 3. **对象状态预检查** ```sql -- 在主库编译失效对象 BEGIN DBMS_UTILITY.COMPILE_SCHEMA(schema => 'YOUR_SCHEMA'); END; -- 检查备库对象状态 SELECT OBJECT_NAME, STATUS FROM ALL_OBJECTS WHERE STATUS = 'INVALID' AND OWNER = 'YOUR_SCHEMA'; ``` 4. **帆软配置调整** - 数据连接设置:在帆软设计器中,将数据源连接字符串改为直连主库 - 缓存策略:启用数据集缓存减少实时查询 - SQL优化:避免在查询中包含`SYSDATE`等非确定性函数(可能触发隐式写操作) #### 预防措施 - **读写分离规范**:配置中间件(如Oracle DG Broker)明确区分读写流量 - **结构变更流程**:修改生产环境表结构后,立即手动编译依赖对象 - **备库访问策略**:限制帆软仅执行`SELECT`操作,禁用`EXECUTE`权限 > **关键结论**:ORA-16000本质是**只读环境写操作冲突**。最有效方案是将帆软的DBLINK指向Oracle主库。若必须访问备库,需确保所有对象有效且查询不触发任何隐式维护操作[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值