понедельник, 12 ноября 2018 г.

Oracle Warehousing: копирование таблицы через dblink

Необходимо из таблицы table_remote@dblink объемом 270 ГБ, выбрать только лишь те строки, которые соответствуют строкам из локальной таблицы table_dict.  Результат выборки сохранить в локальную таблицу table_local. Предварительные выборки показали, что результат составит примерно 100 МБ.

На локальном сервере создаём таблицу (table_local), затем, используя анонимный PL/SQL блок и курсор, загружаем отфильтрованные данные из table_remote@dblink:

DECLARE 
  CURSOR cr_data IS 
    SELECT 
           /*+ driving_site(tr)*/ 
           tr.* 
    FROM   table_remote@dblink tr 
    join   table_dict td 
    ON     ( tr.col_1 = td.col_2); 

  TYPE t_cr_row IS TABLE OF cr_data%ROWTYPE; 
  v_cr_row t_cr_row; 
BEGIN 
  OPEN cr_data; 
  LOOP 
    FETCH cr_data BULK COLLECT 
    INTO  v_cr_row limit 10000; 
     
    EXIT WHEN v_cr_row.count = 0; 
    FORALL i IN 1..v_cr_row.count 
    INSERT INTO table_local VALUES v_cr_row(i); 
     
    COMMIT; 
  END LOOP; 
  CLOSE cr_data; 
END;
/

В этом варианте решения следует принять во внимание то, что в списке полей таблицы table_remote@dflink  не должно быть LOB-полей. LOB-поля не возможно выбирать по dblink. При такой попытке возникает ошибка ORA-22992: cannot use LOB locators selected from remote tables. 
Для копирования remote таблиц c LOB-полями необходимо создавать промежуточные таблицы методом CTAS  (CREATE TABLE AS SELECT).

Рассмотрим другие варианты решения этой задачи.

1. На локальном сервере запускаем команду на создание промежуточной таблицы с выборкой данных и соединением таблиц - CTAS:

   CREATE TABLE table_local AS 
  SELECT /*+ driving_site(tr)*/ tr.* 
  FROM   table_remote@dblink tr 
         join table_dict td 
           ON ( tr.col_1 = td.col_2 ); 
   
Используя хинт driving_site мы просим СУБД выполнить соединение таблиц на удаленном сервере, предполагая, что переправка данных таблицы table_dict займет меньше времени, чем переправка данных таблицы table_remote@dblink объёмом 270 ГБ. Но это решение не будет работать, потому что хинт driving_site в DDL  не будет функционировать.
   
2. На локальном сервере создаём таблицу, затем используя INSERT, загружаем отфильтрованные данные из table_remote@dblink :

INSERT INTO table_local 
SELECT /*+ driving_site(tr)*/ tr.* 
FROM   table_remote@dblink tr 
       join table_dict td 
         ON ( tr.col_1 = td.col_2 );  

Это решение также не является оптимальным по той же причине - хинт driving_site не будет работать в DML.