Преодоление ограничения на массовые вставки по ссылке в базе данных

Кажется, что есть ограничение реализации, которое запрещает использование forall .. insert в Oracle, когда используется через ссылку на базу данных. Это простой пример для демонстрации:

connect schema/password@db1

create table tmp_ben_test (
   a number
 , b number
 , c date
 , constraint pk_tmp_ben_test primary key (a, b)
    );

Table created.

connect schema/password@db2
Connected.

declare

   type r_test is record ( a number, b number, c date);
   type t__test is table of r_test index by binary_integer;
   t_test t__test;

   cursor c_test is
    select 1, level, sysdate
      from dual
   connect by level <= 10
           ;

begin

   open c_test;
   fetch c_test bulk collect into t_test;

   forall i in t_test.first .. t_test.last
     insert into tmp_ben_test@db1
     values t_test(i)
            ;

   close c_test;

end;
/

Очень смущает, что это не удается в 9i со следующей ошибкой:

ОШИБКА в строке 1: ORA-01400: невозможно вставить NULL в ("SCHEMA"."TMP_BEN_TEST"."A") ORA-02063: предыдущая строка из DB1 ORA-06512: в строке 18

Если только после проверки в 11g я понял, что это ограничение реализации.

ОШИБКА в строке 18: ORA-06550: строка 18, столбец 4: PLS-00739: FORALL INSERT/UPDATE/DELETE не поддерживается в удаленных таблицах

Действительно очевидный способ обойти это изменить forall .. чтобы:

for i in t_test.first .. t_test.last loop
    insert into tmp_ben_test@db1
    values t_test(i);
end loop;

но я бы предпочел сохранить его до одной вставки, если это вообще возможно. Том Кайт предлагает использовать глобальную временную таблицу. Вставка данных в GTT, а затем по каналу связи с БД выглядит огромным перебором для набора данных, который уже имеет пользовательский тип.

Просто пояснить этот пример чрезвычайно просто по сравнению с тем, что на самом деле происходит. Мы никак не сможем сделать простой insert into и нет никакого способа, которым все операции могли бы быть сделаны на GTT. Большие части кода должны быть выполнены в пользовательском типе.

Есть ли другой, более простой или менее DMLy способ обойти это ограничение?

2 ответа

Решение

С какими ограничениями вы сталкиваетесь в удаленной базе данных? Если вы можете создавать объекты там, у вас есть обходной путь: в удаленной базе данных создайте тип коллекции и процедуру, которая принимает коллекцию в качестве параметра и выполняет инструкцию FORALL.

Если вы создадите тип t__test/r_test в db2, а затем создадите для них общий синоним для db1, то вы сможете вызвать процедуру из db1 в db2, заполнив таблицу t_table и вернувшись в db1. Тогда вы сможете вставить в локальную таблицу.

Я предполагаю, что вы будете использовать упакованные типы и процедуры в реальном мире, а не анонимные блоки.

Кроме того, это не было бы идеальным решением для больших наборов данных, тогда GTT или подобное было бы лучше.

Другие вопросы по тегам