Выберите и вставьте через dblink

У меня возникли проблемы с выбором для вставки через dblink в оракуле 10. Я использую следующий оператор:

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

Когда я запускаю оператор, на удаленном сервере в ссылке на БД запускается следующее:

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")

Проблема заключается в том, что в случае вставки таблица enitre вытягивается через dblink, а затем ограничивается локально, что занимает немало времени, учитывая размер таблицы. Есть ли причина, по которой добавление вставки изменит поведение таким образом?


person Domtar    schedule 17.03.2010    source источник


Ответы (6)


Вы можете использовать подсказку Driving_site. Здесь есть хорошее объяснение: http://www.dba-oracle.com/t_sql_dblink_performance.htm

person Rene    schedule 17.03.2010
comment
Я попытался добавить следующую подсказку к исходному запросу перед публикацией, но получил те же результаты. /*+DRIVING_SITE(s)*/ Это правильно намекает на то, что нужно ехать на стороне dblink? - person Domtar; 17.03.2010

Когда дело доходит до DML, oracle предпочитает игнорировать любую подсказку Driving_site и выполняет оператор на целевом сайте. Поэтому я сомневаюсь, что вы сможете это изменить (даже используя подход WITH, описанный выше). Возможный обходной путь: вы можете создать синоним для LOCAL.TABLE1 в удаленной базе данных и использовать его в инструкции INSERT.

person Community    schedule 17.03.2010

Использование предложения 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
person T.j.    schedule 17.03.2010
comment
Этот ответ показывает, что ваш синтаксис здесь неверен. - person Alfabravo; 04.08.2016

Oracle будет игнорировать подсказку Driving_site для операторов вставки, так как DML всегда выполняется локально. Способ сделать это состоит в том, чтобы создать курсор с подсказкой сайта вождения, а затем пройтись по курсору с помощью bulkcollect/forall и вставить в целевую локальную таблицу.

person NMR    schedule 23.10.2013

Насколько велика 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;
/
person Gary Myers    schedule 18.03.2010
comment
Это был мой первоначальный подход, но в рабочей таблице может быть более 1000 элементов. Я думаю, что мне придется разбить обработку на группы по 1000, чтобы не выходить за границы. - person Domtar; 18.03.2010
comment
Вы можете создать глобальную временную таблицу на удаленной стороне ссылки? Вы можете вставить это из рабочего стола, тогда все соединение будет на удаленной стороне. - person Gary Myers; 19.03.2010

Вставка в подсказку кардинальности 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
person Lavallee Alain    schedule 13.02.2013