【问题标题】:Select and Insert across dblink跨 dblink 选择和插入
【发布时间】:2010-03-17 14:15:11
【问题描述】:

我在 oracle 10 的 dblink 中选择插入插入时遇到了一些问题。我正在使用以下语句:

INSERT INTO LOCAL.TABLE_1 ( COL1, COL2) 
SELECT  COL1, COL2
FROM REMOTE.TABLE1@dblink s
WHERE COL1 IN ( SELECT COL1 FROM WORKING_TABLE)

当我运行语句时,以下是在 DB Link 上针对远程服务器运行的语句:

SELECT /*+ OPAQUE_TRANSFORM */ "COL1", "COL2"
FROM "REMOTE"."TABLE1" "S"

如果我只运行选择而不执行插入,则运行以下内容:

SELECT /*+ */ "A1"."COL1"
     , "A1"."COL2"
  FROM "REMOTE"."TABLE1" "A1"
 WHERE "A1"."COL1" =
   ANY ( SELECT "A2"."COL1"
       FROM "LOCAL"."TABLE1"@! "A2")

问题是在插入的情况下,整个表被拉过 dblink,然后限制了本地化,考虑到表的大小,这需要相当长的时间。是否有任何理由添加插入会以这种方式改变行为?

【问题讨论】:

    标签: oracle insert dblink


    【解决方案1】:

    您可能需要使用driving_site 提示。这里有一个很好的解释: http://www.dba-oracle.com/t_sql_dblink_performance.htm

    【讨论】:

    • 我曾尝试在发布之前将以下提示添加到初始查询中,但得到了相同的结果。 /*+DRIVING_SITE(s)*/ 那暗示在 dblink 端驱动对吗?
    【解决方案2】:

    当涉及到 DML 时,oracle 选择忽略任何driving_site 提示并在目标站点执行语句。所以我怀疑你是否能够改变它(即使使用上面描述的 WITH 方法)。一种可能的解决方法是您可以在远程数据库上创建 LOCAL.TABLE1 的同义词,并在 INSERT 语句中使用它。

    【讨论】:

      【解决方案3】:

      利用 WITH 子句可以优化您对工作集的检索:

      WITH remote_rows AS
           (SELECT /*+DRIVING_SITE(s)*/COL1, COL2
            FROM REMOTE.TABLE1@dblink s
            WHERE COL1 IN ( SELECT COL1 FROM WORKING_TABLE)) 
      INSERT INTO LOCAL.TABLE_1 ( COL1, COL2)
      SELECT  COL1, COL2
      FROM remote_rows
      

      【讨论】:

      【解决方案4】:

      Oracle 将忽略 insert 语句的driving_site 提示,因为 DML 始终在本地执行。这样做的方法是使用驱动站点提示创建一个游标,然后使用 bulkcollect/forall 循环遍历游标并插入到目标本地表中。

      【讨论】:

        【解决方案5】:

        WORKING_TABLE 有多大? 如果它足够小,您可以尝试从 work_table 中选择一个集合,然后将该集合的元素作为 IN 列表中的元素传递。

        declare
          TYPE t_type IS TABLE OF VARCHAR2(60);
          v_coll t_type;
        begin
          dbms_application_info.set_module('TEST','TEST');
          --
          select distinct object_type 
          bulk collect into v_coll
          from user_objects;
          --
          IF v_coll.count > 20 THEN
            raise_application_error(-20001,'You need '||v_coll.count||' elements in the IN list');
          ELSE
            v_coll.extend(20);
          END IF;
          insert into abc (object_type, object_name)
          select object_type, object_name
          from user_objects@tmfprd
          where object_type in 
                    (v_coll(1), v_coll(2), v_coll(3), v_coll(4), v_coll(5), 
                    v_coll(6), v_coll(7), v_coll(8), v_coll(9), v_coll(10),
                    v_coll(11), v_coll(12), v_coll(13), v_coll(14), v_coll(15), 
                    v_coll(16), v_coll(17), v_coll(18), v_coll(19), v_coll(20)
                     );
          --
          dbms_output.put_line(sql%rowcount);
        end;
        /
        

        【讨论】:

        • 这是我最初的方法,但工作表中可能有 1000 多个元素。我想我必须将处理分成 1000 组,以保持在限制范围内。
        • 你能在链接的远端创建一个全局临时表吗?您可以从工作表中插入,然后连接都将在远程端。
        【解决方案6】:

        插入 zith 基数提示似乎在 11.2 中有效

         INSERT /*+ append */  
                INTO MIG_CGD30_TEST       
                        SELECT  /*+ cardinality(ZFD 400000) cardinality(CGD 60000000)*/ 
                    TRIM (CGD.NUMCPT) AS NUMCPT, TRIM (ZFD.NUMBDC_NEW) AS NUMBDC
                      FROM CGD30@DBL_MIG_THALER CGD,
                           ZFD10@DBL_MIG_THALER ZFD,
                           EVD01_ADS_DR3W2  EVD
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-10-27
          • 1970-01-01
          • 2016-08-04
          • 1970-01-01
          • 2018-12-11
          • 1970-01-01
          • 1970-01-01
          • 2014-05-27
          相关资源
          最近更新 更多